Commit ca6925d8 authored by Joel Hockey's avatar Joel Hockey Committed by Commit Bot

Move crostini shared path state into background

Convert Crostini to a class, and move state into bg so that all
FilesApp windows will have a consistent view of which paths are shared.

Bug: 878324
Change-Id: I3c21465b625091fd6360e6b799d9e85baf1ea614
Reviewed-on: https://chromium-review.googlesource.com/c/1335747
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Reviewed-by: default avatarSam McNally <sammc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608270}
parent bde2b01f
...@@ -215,5 +215,5 @@ IN_PROC_BROWSER_TEST_F(FileManagerJsTest, UtilTest) { ...@@ -215,5 +215,5 @@ IN_PROC_BROWSER_TEST_F(FileManagerJsTest, UtilTest) {
} }
IN_PROC_BROWSER_TEST_F(FileManagerJsTest, Crostini) { IN_PROC_BROWSER_TEST_F(FileManagerJsTest, Crostini) {
RunGeneratedTest("/foreground/js/crostini_unittest.html"); RunGeneratedTest("/background/js/crostini_unittest.html");
} }
// 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.
/**
* Crostini shared path state handler.
* @constructor
*/
function Crostini() {}
/**
* Set from feature 'crostini-files'.
* @param {boolean} enabled
*/
Crostini.prototype.setEnabled = function(enabled) {};
/**
* @return {boolean} Whether crostini is enabled.
*/
Crostini.prototype.isEnabled = function() {};
/**
* Registers an entry as a shared path.
* @param {!Entry} entry
*/
Crostini.prototype.registerSharedPath = function(entry) {};
/**
* Unregisters entry as a shared path.
* @param {!Entry} entry
*/
Crostini.prototype.unregisterSharedPath = function(entry) {};
/**
* Returns true if entry is shared.
* @param {!Entry} entry
* @return {boolean} True if path is shared either by a direct
* share or from one of its ancestor directories.
*/
Crostini.prototype.isPathShared = function(entry) {};
/**
* Returns true if entry can be shared with Crostini.
* @param {!Entry} entry
* @param {boolean} persist If path is to be persisted.
*/
Crostini.prototype.canSharePath = function(entry, persist) {};
...@@ -44,3 +44,8 @@ FileBrowserBackgroundFull.prototype.mediaScanner; ...@@ -44,3 +44,8 @@ FileBrowserBackgroundFull.prototype.mediaScanner;
* @type {!importer.HistoryLoader} * @type {!importer.HistoryLoader}
*/ */
FileBrowserBackgroundFull.prototype.historyLoader; FileBrowserBackgroundFull.prototype.historyLoader;
/**
* @type {!Crostini}
*/
FileBrowserBackgroundFull.prototype.crostini;
...@@ -107,3 +107,8 @@ CommandHandlerDeps.prototype.getSelection = function() {}; ...@@ -107,3 +107,8 @@ CommandHandlerDeps.prototype.getSelection = function() {};
* @type {MetadataModel} * @type {MetadataModel}
*/ */
CommandHandlerDeps.prototype.metadataModel; CommandHandlerDeps.prototype.metadataModel;
/**
* @type {Crostini}
*/
CommandHandlerDeps.prototype.crostini;
...@@ -36,6 +36,7 @@ js_type_check("closure_compile_module") { ...@@ -36,6 +36,7 @@ js_type_check("closure_compile_module") {
":background", ":background",
":background_base", ":background_base",
":closure_compile_externs", ":closure_compile_externs",
":crostini",
":device_handler", ":device_handler",
":drive_sync_handler", ":drive_sync_handler",
":duplicate_finder", ":duplicate_finder",
...@@ -96,6 +97,7 @@ js_library("background") { ...@@ -96,6 +97,7 @@ js_library("background") {
deps = [ deps = [
":app_windows", ":app_windows",
":background_base", ":background_base",
":crostini",
":device_handler", ":device_handler",
":drive_sync_handler", ":drive_sync_handler",
":duplicate_finder", ":duplicate_finder",
...@@ -124,6 +126,22 @@ js_library("background_base") { ...@@ -124,6 +126,22 @@ js_library("background_base") {
] ]
} }
js_library("crostini") {
deps = [
"../../common/js:metrics",
"//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/externs:volume_manager",
]
}
js_unittest("crostini_unittest") {
deps = [
":crostini",
"../../common/js:mock_entry",
"//ui/webui/resources/js:webui_resource_test",
]
}
js_library("device_handler") { js_library("device_handler") {
deps = [ deps = [
":volume_manager_factory", ":volume_manager_factory",
...@@ -333,6 +351,7 @@ js_library("volume_manager_util") { ...@@ -333,6 +351,7 @@ js_library("volume_manager_util") {
js_unit_tests("unit_tests") { js_unit_tests("unit_tests") {
deps = [ deps = [
":crostini_unittest",
":volume_manager_unittest", ":volume_manager_unittest",
] ]
} }
...@@ -82,6 +82,9 @@ function FileBrowserBackgroundImpl() { ...@@ -82,6 +82,9 @@ function FileBrowserBackgroundImpl() {
this.progressCenter, this.historyLoader, this.dispositionChecker_, this.progressCenter, this.historyLoader, this.dispositionChecker_,
this.driveSyncHandler); this.driveSyncHandler);
/** @type {!Crostini} */
this.crostini = new Crostini();
/** /**
* String assets. * String assets.
* @type {Object<string>} * @type {Object<string>}
...@@ -101,7 +104,7 @@ function FileBrowserBackgroundImpl() { ...@@ -101,7 +104,7 @@ function FileBrowserBackgroundImpl() {
chrome.contextMenus.onClicked.addListener( chrome.contextMenus.onClicked.addListener(
this.onContextMenuClicked_.bind(this)); this.onContextMenuClicked_.bind(this));
// Initializa string and volume manager related stuffs. // Initialize string and volume manager related stuffs.
this.initializationPromise_.then(function(strings) { this.initializationPromise_.then(function(strings) {
this.stringData = strings; this.stringData = strings;
this.initContextMenu_(); this.initContextMenu_();
...@@ -110,6 +113,9 @@ function FileBrowserBackgroundImpl() { ...@@ -110,6 +113,9 @@ function FileBrowserBackgroundImpl() {
volumeManager.addEventListener( volumeManager.addEventListener(
VolumeManagerCommon.VOLUME_ALREADY_MOUNTED, VolumeManagerCommon.VOLUME_ALREADY_MOUNTED,
this.handleViewEvent_.bind(this)); this.handleViewEvent_.bind(this));
this.crostini.init(volumeManager);
this.crostini.listen();
}.bind(this)); }.bind(this));
this.fileOperationManager = new FileOperationManager(); this.fileOperationManager = new FileOperationManager();
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// <include src="../../common/js/progress_center_common.js"> // <include src="../../common/js/progress_center_common.js">
// <include src="../../common/js/importer_common.js"> // <include src="../../common/js/importer_common.js">
// <include src="metadata_proxy.js"> // <include src="metadata_proxy.js">
// <include src="crostini.js">
// <include src="device_handler.js"> // <include src="device_handler.js">
// <include src="drive_sync_handler.js"> // <include src="drive_sync_handler.js">
// <include src="duplicate_finder.js"> // <include src="duplicate_finder.js">
......
...@@ -2,18 +2,28 @@ ...@@ -2,18 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
const Crostini = {};
/** /**
* Set from cmd line flag 'crostini-files'. * Crostini shared path state handler.
* @type {boolean} * @constructor
*/ */
Crostini.IS_CROSTINI_FILES_ENABLED = false; function Crostini() {
/** @private {boolean} */
this.enabled_ = false;
/**
* Maintains a list of paths shared with the crostini container.
* Keyed by VolumeManagerCommon.RootType, with boolean set values
* of string paths. e.g. {'Downloads': {'/foo': true, '/bar': true}}.
* @private @dict {!Object<!Object<boolean>>}
*/
this.shared_paths_ = {};
}
/** /**
* Keep in sync with histograms.xml:FileBrowserCrostiniSharedPathsDepth * Keep in sync with histograms.xml:FileBrowserCrostiniSharedPathsDepth
* histogram_suffix. * histogram_suffix.
* @type {!Map<VolumeManagerCommon.RootType, string>} * @type {!Map<VolumeManagerCommon.RootType, string>}
* @const
*/ */
Crostini.VALID_ROOT_TYPES_FOR_SHARE = new Map([ Crostini.VALID_ROOT_TYPES_FOR_SHARE = new Map([
[VolumeManagerCommon.RootType.DOWNLOADS, 'Downloads'], [VolumeManagerCommon.RootType.DOWNLOADS, 'Downloads'],
...@@ -21,16 +31,18 @@ Crostini.VALID_ROOT_TYPES_FOR_SHARE = new Map([ ...@@ -21,16 +31,18 @@ Crostini.VALID_ROOT_TYPES_FOR_SHARE = new Map([
]); ]);
/** /**
* Can be collapsed into VALD_ROOT_TYPES_FOR_SHARE once * Can be collapsed into VALID_ROOT_TYPES_FOR_SHARE once
* DriveFS flag is removed. * DriveFS flag is removed.
* Keep in sync with histograms.xml:FileBrowserCrostiniSharedPathsDepth * Keep in sync with histograms.xml:FileBrowserCrostiniSharedPathsDepth
* histogram_suffix. * histogram_suffix.
* @type {!Map<VolumeManagerCommon.RootType, string>} * @type {!Map<VolumeManagerCommon.RootType, string>}
* @const
*/ */
Crostini.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE = new Map([ Crostini.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE = new Map([
[VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT, 'DriveComputers'], [VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT, 'DriveComputers'],
[VolumeManagerCommon.RootType.COMPUTER, 'DriveComputers'], [VolumeManagerCommon.RootType.COMPUTER, 'DriveComputers'],
[VolumeManagerCommon.RootType.DRIVE, 'MyDrive'], [VolumeManagerCommon.RootType.DRIVE, 'MyDrive'],
[VolumeManagerCommon.RootType.TEAM_DRIVES_GRAND_ROOT, 'TeamDrive'],
[VolumeManagerCommon.RootType.TEAM_DRIVE, 'TeamDrive'], [VolumeManagerCommon.RootType.TEAM_DRIVE, 'TeamDrive'],
]); ]);
...@@ -38,26 +50,48 @@ Crostini.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE = new Map([ ...@@ -38,26 +50,48 @@ Crostini.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE = new Map([
Crostini.UMA_ROOT_TYPE_OTHER = 'Other'; Crostini.UMA_ROOT_TYPE_OTHER = 'Other';
/** /**
* Maintains a list of paths shared with the crostini container. * Initialize Volume Manager.
* Keyed by VolumeManagerCommon.RootType, with boolean set values * @param {!VolumeManager} volumeManager
* of string paths. e.g. {'Downloads': {'/foo': true, '/bar': true}}. */
* @private @dict {!Object<!Object<boolean>>} Crostini.prototype.init = function(volumeManager) {
this.volumeManager_ = volumeManager;
};
/**
* Register for any shared path changes.
*/
Crostini.prototype.listen = function() {
chrome.fileManagerPrivate.onCrostiniSharedPathsChanged.addListener(
this.onChange_.bind(this));
};
/**
* Set from feature 'crostini-files'.
* @param {boolean} enabled
*/
Crostini.prototype.setEnabled = function(enabled) {
this.enabled_ = enabled;
};
/**
* @return {boolean} Whether crostini is enabled.
*/ */
Crostini.SHARED_PATHS_ = {}; Crostini.prototype.isEnabled = function() {
return this.enabled_;
};
/** /**
* Registers an entry as a shared path. * Registers an entry as a shared path.
* @param {!Entry} entry * @param {!Entry} entry
* @param {!VolumeManager} volumeManager
*/ */
Crostini.registerSharedPath = function(entry, volumeManager) { Crostini.prototype.registerSharedPath = function(entry) {
const info = volumeManager.getLocationInfo(entry); const info = this.volumeManager_.getLocationInfo(entry);
if (!info) if (!info)
return; return;
let paths = Crostini.SHARED_PATHS_[info.rootType]; let paths = this.shared_paths_[info.rootType];
if (!paths) { if (!paths) {
paths = {}; paths = {};
Crostini.SHARED_PATHS_[info.rootType] = paths; this.shared_paths_[info.rootType] = paths;
} }
// Remove any existing paths that are children of the new path. // Remove any existing paths that are children of the new path.
for (let path in paths) { for (let path in paths) {
...@@ -78,13 +112,12 @@ Crostini.registerSharedPath = function(entry, volumeManager) { ...@@ -78,13 +112,12 @@ Crostini.registerSharedPath = function(entry, volumeManager) {
/** /**
* Unregisters entry as a shared path. * Unregisters entry as a shared path.
* @param {!Entry} entry * @param {!Entry} entry
* @param {!VolumeManager} volumeManager
*/ */
Crostini.unregisterSharedPath = function(entry, volumeManager) { Crostini.prototype.unregisterSharedPath = function(entry) {
const info = volumeManager.getLocationInfo(entry); const info = this.volumeManager_.getLocationInfo(entry);
if (!info) if (!info)
return; return;
const paths = Crostini.SHARED_PATHS_[info.rootType]; const paths = this.shared_paths_[info.rootType];
if (paths) { if (paths) {
delete paths[entry.fullPath]; delete paths[entry.fullPath];
} }
...@@ -92,17 +125,17 @@ Crostini.unregisterSharedPath = function(entry, volumeManager) { ...@@ -92,17 +125,17 @@ Crostini.unregisterSharedPath = function(entry, volumeManager) {
/** /**
* Handles shared path changes. * Handles shared path changes.
* @param {!VolumeManager} volumeManager
* @param {chrome.fileManagerPrivate.CrostiniSharedPathsChangedEvent} event * @param {chrome.fileManagerPrivate.CrostiniSharedPathsChangedEvent} event
* @private
*/ */
Crostini.onSharedPathsChanged = function(volumeManager, event) { Crostini.prototype.onChange_ = function(event) {
if (event.eventType === 'share') { if (event.eventType === 'share') {
for (const entry of event.entries) { for (const entry of event.entries) {
Crostini.registerSharedPath(entry, volumeManager); this.registerSharedPath(entry);
} }
} else if (event.eventType === 'unshare') { } else if (event.eventType === 'unshare') {
for (const entry of event.entries) { for (const entry of event.entries) {
Crostini.unregisterSharedPath(entry, volumeManager); this.unregisterSharedPath(entry);
} }
} }
}; };
...@@ -110,13 +143,12 @@ Crostini.onSharedPathsChanged = function(volumeManager, event) { ...@@ -110,13 +143,12 @@ Crostini.onSharedPathsChanged = function(volumeManager, event) {
/** /**
* Returns true if entry is shared. * Returns true if entry is shared.
* @param {!Entry} entry * @param {!Entry} entry
* @param {!VolumeManager} volumeManager
* @return {boolean} True if path is shared either by a direct * @return {boolean} True if path is shared either by a direct
* share or from one of its ancestor directories. * share or from one of its ancestor directories.
*/ */
Crostini.isPathShared = function(entry, volumeManager) { Crostini.prototype.isPathShared = function(entry) {
const root = volumeManager.getLocationInfo(entry).rootType; const root = this.volumeManager_.getLocationInfo(entry).rootType;
const paths = Crostini.SHARED_PATHS_[root]; const paths = this.shared_paths_[root];
if (!paths) if (!paths)
return false; return false;
// Check path and all ancestor directories. // Check path and all ancestor directories.
...@@ -129,26 +161,13 @@ Crostini.isPathShared = function(entry, volumeManager) { ...@@ -129,26 +161,13 @@ Crostini.isPathShared = function(entry, volumeManager) {
return !!paths['/']; return !!paths['/'];
}; };
/**
* @param {!Entry} entry
* @param {!VolumeManager} volumeManager
* @return {boolean} True if the entry is from crostini.
*/
Crostini.isCrostiniEntry = function(entry, volumeManager) {
return volumeManager.getLocationInfo(entry).rootType ===
VolumeManagerCommon.RootType.CROSTINI;
};
/** /**
* Returns true if entry can be shared with Crostini. * Returns true if entry can be shared with Crostini.
* @param {!Entry} entry * @param {!Entry} entry
* @param {boolean} persist If path is to be persisted. * @param {boolean} persist If path is to be persisted.
* @param {!VolumeManager} volumeManager
*/ */
Crostini.canSharePath = function(entry, persist, volumeManager) { Crostini.prototype.canSharePath = function(entry, persist) {
if (!this.enabled_)
// Check crostini-files flag and valid volume.
if (!Crostini.IS_CROSTINI_FILES_ENABLED)
return false; return false;
// Only directories for persistent shares. // Only directories for persistent shares.
...@@ -156,20 +175,8 @@ Crostini.canSharePath = function(entry, persist, volumeManager) { ...@@ -156,20 +175,8 @@ Crostini.canSharePath = function(entry, persist, volumeManager) {
return false; return false;
// Allow Downloads, and Drive if DriveFS is enabled. // Allow Downloads, and Drive if DriveFS is enabled.
const rootType = volumeManager.getLocationInfo(entry).rootType; const rootType = this.volumeManager_.getLocationInfo(entry).rootType;
return Crostini.VALID_ROOT_TYPES_FOR_SHARE.has(rootType) || return Crostini.VALID_ROOT_TYPES_FOR_SHARE.has(rootType) ||
(loadTimeData.getBoolean('DRIVE_FS_ENABLED') && (loadTimeData.getBoolean('DRIVE_FS_ENABLED') &&
Crostini.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE.has(rootType)); Crostini.VALID_DRIVE_FS_ROOT_TYPES_FOR_SHARE.has(rootType));
}; };
/**
* Returns true if task requires entries to be shared before executing task.
* @param {!chrome.fileManagerPrivate.FileTask} task Task to run.
* @return {boolean} true if task requires entries to be shared.
*/
Crostini.taskRequiresSharing = function(task) {
const taskParts = task.taskId.split('|');
const taskType = taskParts[1];
const actionId = taskParts[2];
return taskType === 'crostini' || actionId === 'install-linux-package';
};
...@@ -20,6 +20,10 @@ const volumeManager = /** @type {!VolumeManager} */ ({ ...@@ -20,6 +20,10 @@ const volumeManager = /** @type {!VolumeManager} */ ({
}, },
}); });
const crostini = new Crostini();
crostini.init(volumeManager);
function testIsPathShared() { function testIsPathShared() {
const mockFileSystem = new MockFileSystem('volumeId'); const mockFileSystem = new MockFileSystem('volumeId');
const root = new MockDirectoryEntry(mockFileSystem, '/'); const root = new MockDirectoryEntry(mockFileSystem, '/');
...@@ -29,58 +33,57 @@ function testIsPathShared() { ...@@ -29,58 +33,57 @@ function testIsPathShared() {
const b = new MockDirectoryEntry(mockFileSystem, '/b'); const b = new MockDirectoryEntry(mockFileSystem, '/b');
const bb = new MockDirectoryEntry(mockFileSystem, '/b/b'); const bb = new MockDirectoryEntry(mockFileSystem, '/b/b');
assertFalse(Crostini.isPathShared(a, volumeManager)); assertFalse(crostini.isPathShared(a));
Crostini.registerSharedPath(a, volumeManager); crostini.registerSharedPath(a);
assertFalse(Crostini.isPathShared(root, volumeManager)); assertFalse(crostini.isPathShared(root));
assertTrue(Crostini.isPathShared(a, volumeManager)); assertTrue(crostini.isPathShared(a));
assertTrue(Crostini.isPathShared(aa, volumeManager)); assertTrue(crostini.isPathShared(aa));
Crostini.registerSharedPath(bb, volumeManager); crostini.registerSharedPath(bb);
assertFalse(Crostini.isPathShared(b, volumeManager)); assertFalse(crostini.isPathShared(b));
assertTrue(Crostini.isPathShared(bb, volumeManager)); assertTrue(crostini.isPathShared(bb));
Crostini.unregisterSharedPath(bb, volumeManager); crostini.unregisterSharedPath(bb);
assertFalse(Crostini.isPathShared(bb, volumeManager)); assertFalse(crostini.isPathShared(bb));
// Test collapsing. Setup with /a/a, /a/b, /b // Test collapsing. Setup with /a/a, /a/b, /b
Crostini.unregisterSharedPath(a, volumeManager); crostini.unregisterSharedPath(a);
Crostini.registerSharedPath(aa, volumeManager); crostini.registerSharedPath(aa);
Crostini.registerSharedPath(ab, volumeManager); crostini.registerSharedPath(ab);
Crostini.registerSharedPath(b, volumeManager); crostini.registerSharedPath(b);
assertFalse(Crostini.isPathShared(a, volumeManager)); assertFalse(crostini.isPathShared(a));
assertTrue(Crostini.isPathShared(aa, volumeManager)); assertTrue(crostini.isPathShared(aa));
assertTrue(Crostini.isPathShared(ab, volumeManager)); assertTrue(crostini.isPathShared(ab));
assertTrue(Crostini.isPathShared(b, volumeManager)); assertTrue(crostini.isPathShared(b));
// Add /a, collapses /a/a, /a/b // Add /a, collapses /a/a, /a/b
Crostini.registerSharedPath(a, volumeManager); crostini.registerSharedPath(a);
assertTrue(Crostini.isPathShared(a, volumeManager)); assertTrue(crostini.isPathShared(a));
assertTrue(Crostini.isPathShared(aa, volumeManager)); assertTrue(crostini.isPathShared(aa));
assertTrue(Crostini.isPathShared(ab, volumeManager)); assertTrue(crostini.isPathShared(ab));
assertTrue(Crostini.isPathShared(b, volumeManager)); assertTrue(crostini.isPathShared(b));
// Unregister /a, /a/a and /a/b should be lost. // Unregister /a, /a/a and /a/b should be lost.
Crostini.unregisterSharedPath(a, volumeManager); crostini.unregisterSharedPath(a);
assertFalse(Crostini.isPathShared(a, volumeManager)); assertFalse(crostini.isPathShared(a));
assertFalse(Crostini.isPathShared(aa, volumeManager)); assertFalse(crostini.isPathShared(aa));
assertFalse(Crostini.isPathShared(ab, volumeManager)); assertFalse(crostini.isPathShared(ab));
assertTrue(Crostini.isPathShared(b, volumeManager)); assertTrue(crostini.isPathShared(b));
// Register root, collapses all. // Register root, collapses all.
Crostini.registerSharedPath(root, volumeManager); crostini.registerSharedPath(root);
assertTrue(Crostini.isPathShared(a, volumeManager)); assertTrue(crostini.isPathShared(a));
assertTrue(Crostini.isPathShared(aa, volumeManager)); assertTrue(crostini.isPathShared(aa));
assertTrue(Crostini.isPathShared(ab, volumeManager)); assertTrue(crostini.isPathShared(ab));
assertTrue(Crostini.isPathShared(b, volumeManager)); assertTrue(crostini.isPathShared(b));
// Unregister root, all should be lost. // Unregister root, all should be lost.
Crostini.unregisterSharedPath(root, volumeManager); crostini.unregisterSharedPath(root);
assertFalse(Crostini.isPathShared(a, volumeManager)); assertFalse(crostini.isPathShared(a));
assertFalse(Crostini.isPathShared(aa, volumeManager)); assertFalse(crostini.isPathShared(aa));
assertFalse(Crostini.isPathShared(ab, volumeManager)); assertFalse(crostini.isPathShared(ab));
assertFalse(Crostini.isPathShared(b, volumeManager)); assertFalse(crostini.isPathShared(b));
} }
function testCanSharePath() { function testCanSharePath() {
Crostini.IS_CROSTINI_FILES_ENABLED = true; crostini.setEnabled(true);
const mockFileSystem = new MockFileSystem('test'); const mockFileSystem = new MockFileSystem('test');
const root = new MockDirectoryEntry(mockFileSystem, '/'); const root = new MockDirectoryEntry(mockFileSystem, '/');
...@@ -94,16 +97,16 @@ function testCanSharePath() { ...@@ -94,16 +97,16 @@ function testCanSharePath() {
disallowed.set('test', 'test'); disallowed.set('test', 'test');
for (let type of disallowed.keys()) { for (let type of disallowed.keys()) {
volumeManagerRootType = type; volumeManagerRootType = type;
assertFalse(Crostini.canSharePath(root, true, volumeManager)); assertFalse(crostini.canSharePath(root, true));
assertFalse(Crostini.canSharePath(root, false, volumeManager)); assertFalse(crostini.canSharePath(root, false));
assertFalse(Crostini.canSharePath(rootFile, true, volumeManager)); assertFalse(crostini.canSharePath(rootFile, true));
assertFalse(Crostini.canSharePath(rootFile, false, volumeManager)); assertFalse(crostini.canSharePath(rootFile, false));
assertFalse(Crostini.canSharePath(rootFolder, true, volumeManager)); assertFalse(crostini.canSharePath(rootFolder, true));
assertFalse(Crostini.canSharePath(rootFolder, false, volumeManager)); assertFalse(crostini.canSharePath(rootFolder, false));
assertFalse(Crostini.canSharePath(fooFile, true, volumeManager)); assertFalse(crostini.canSharePath(fooFile, true));
assertFalse(Crostini.canSharePath(fooFile, false, volumeManager)); assertFalse(crostini.canSharePath(fooFile, false));
assertFalse(Crostini.canSharePath(fooFolder, true, volumeManager)); assertFalse(crostini.canSharePath(fooFolder, true));
assertFalse(Crostini.canSharePath(fooFolder, false, volumeManager)); assertFalse(crostini.canSharePath(fooFolder, false));
} }
window.loadTimeData.data['DRIVE_FS_ENABLED'] = true; window.loadTimeData.data['DRIVE_FS_ENABLED'] = true;
...@@ -113,26 +116,15 @@ function testCanSharePath() { ...@@ -113,26 +116,15 @@ function testCanSharePath() {
]); ]);
for (let type of allowed.keys()) { for (let type of allowed.keys()) {
volumeManagerRootType = type; volumeManagerRootType = type;
assertTrue(Crostini.canSharePath(root, true, volumeManager)); assertTrue(crostini.canSharePath(root, true));
assertTrue(Crostini.canSharePath(root, false, volumeManager)); assertTrue(crostini.canSharePath(root, false));
assertFalse(Crostini.canSharePath(rootFile, true, volumeManager)); assertFalse(crostini.canSharePath(rootFile, true));
assertTrue(Crostini.canSharePath(rootFile, false, volumeManager)); assertTrue(crostini.canSharePath(rootFile, false));
assertTrue(Crostini.canSharePath(rootFolder, true, volumeManager)); assertTrue(crostini.canSharePath(rootFolder, true));
assertTrue(Crostini.canSharePath(rootFolder, false, volumeManager)); assertTrue(crostini.canSharePath(rootFolder, false));
assertFalse(Crostini.canSharePath(fooFile, true, volumeManager)); assertFalse(crostini.canSharePath(fooFile, true));
assertTrue(Crostini.canSharePath(fooFile, false, volumeManager)); assertTrue(crostini.canSharePath(fooFile, false));
assertTrue(Crostini.canSharePath(fooFolder, true, volumeManager)); assertTrue(crostini.canSharePath(fooFolder, true));
assertTrue(Crostini.canSharePath(fooFolder, false, volumeManager)); assertTrue(crostini.canSharePath(fooFolder, false));
} }
} }
function task(id) {
return /** @type{!chrome.fileManagerPrivate.FileTask} */ ({taskId: id});
}
function testTaskRequiresSharing() {
assertTrue(Crostini.taskRequiresSharing(task('app|crostini|open-with')));
assertTrue(
Crostini.taskRequiresSharing(task('appId|x|install-linux-package')));
assertFalse(Crostini.taskRequiresSharing(task('appId|x|open-with')));
}
...@@ -28,7 +28,6 @@ js_type_check("closure_compile_module") { ...@@ -28,7 +28,6 @@ js_type_check("closure_compile_module") {
":closure_compile_externs", ":closure_compile_externs",
":column_visibility_controller", ":column_visibility_controller",
":constants", ":constants",
":crostini",
":dialog_action_controller", ":dialog_action_controller",
":dialog_type", ":dialog_type",
":directory_contents", ":directory_contents",
...@@ -84,6 +83,7 @@ js_library("closure_compile_externs") { ...@@ -84,6 +83,7 @@ js_library("closure_compile_externs") {
"$externs_path/metrics_private.js", "$externs_path/metrics_private.js",
"$externs_path/web_animations.js", "$externs_path/web_animations.js",
"../../../externs/app_window_common.js", "../../../externs/app_window_common.js",
"../../../externs/background/crostini.js",
"../../../externs/background/drive_sync_handler.js", "../../../externs/background/drive_sync_handler.js",
"../../../externs/background/file_browser_background.js", "../../../externs/background/file_browser_background.js",
"../../../externs/background/file_browser_background_full.js", "../../../externs/background/file_browser_background_full.js",
...@@ -216,22 +216,6 @@ js_library("dialog_action_controller") { ...@@ -216,22 +216,6 @@ js_library("dialog_action_controller") {
] ]
} }
js_library("crostini") {
deps = [
"../../common/js:metrics",
"//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/externs:volume_manager",
]
}
js_unittest("crostini_unittest") {
deps = [
":crostini",
"../../common/js:mock_entry",
"//ui/webui/resources/js:webui_resource_test",
]
}
js_library("dialog_type") { js_library("dialog_type") {
} }
...@@ -376,7 +360,6 @@ js_library("file_selection") { ...@@ -376,7 +360,6 @@ js_library("file_selection") {
js_library("file_tasks") { js_library("file_tasks") {
deps = [ deps = [
":crostini",
":directory_model", ":directory_model",
":task_history", ":task_history",
"metadata:metadata_model", "metadata:metadata_model",
...@@ -683,7 +666,6 @@ js_library("webui_command_extender") { ...@@ -683,7 +666,6 @@ js_library("webui_command_extender") {
js_unit_tests("unit_tests") { js_unit_tests("unit_tests") {
deps = [ deps = [
":crostini_unittest",
":thumbnail_loader_unittest", ":thumbnail_loader_unittest",
] ]
} }
...@@ -26,6 +26,9 @@ function FileManager() { ...@@ -26,6 +26,9 @@ function FileManager() {
/** @private {importer.HistoryLoader} */ /** @private {importer.HistoryLoader} */
this.historyLoader_ = null; this.historyLoader_ = null;
/** @private {Crostini} */
this.crostini_ = null;
/** /**
* ImportHistory. Non-null only once history observer is added in * ImportHistory. Non-null only once history observer is added in
* {@code addHistoryObserver}. * {@code addHistoryObserver}.
...@@ -497,6 +500,12 @@ FileManager.prototype = /** @struct */ { ...@@ -497,6 +500,12 @@ FileManager.prototype = /** @struct */ {
get historyLoader() { get historyLoader() {
return this.historyLoader_; return this.historyLoader_;
}, },
/**
* @return {Crostini}
*/
get crostini() {
return this.crostini_;
},
/** /**
* @return {importer.ImportRunner} * @return {importer.ImportRunner}
*/ */
...@@ -897,6 +906,7 @@ FileManager.prototype = /** @struct */ { ...@@ -897,6 +906,7 @@ FileManager.prototype = /** @struct */ {
this.fileBrowserBackground_.mediaScanner; this.fileBrowserBackground_.mediaScanner;
this.historyLoader_ = this.historyLoader_ =
this.fileBrowserBackground_.historyLoader; this.fileBrowserBackground_.historyLoader;
this.crostini_ = this.fileBrowserBackground_.crostini;
metrics.recordInterval('Load.InitBackgroundPage'); metrics.recordInterval('Load.InitBackgroundPage');
resolve(); resolve();
}.bind(this)); }.bind(this));
...@@ -1139,13 +1149,9 @@ FileManager.prototype = /** @struct */ { ...@@ -1139,13 +1149,9 @@ FileManager.prototype = /** @struct */ {
// Create task controller. // Create task controller.
this.taskController_ = new TaskController( this.taskController_ = new TaskController(
this.dialogType, this.dialogType, this.volumeManager_, this.ui_, this.metadataModel_,
this.volumeManager_, this.directoryModel_, this.selectionHandler_,
this.ui_, this.metadataUpdateController_, assert(this.crostini_));
this.metadataModel_,
this.directoryModel_,
this.selectionHandler_,
this.metadataUpdateController_);
// Create search controller. // Create search controller.
this.searchController_ = new SearchController( this.searchController_ = new SearchController(
...@@ -1219,8 +1225,6 @@ FileManager.prototype = /** @struct */ { ...@@ -1219,8 +1225,6 @@ FileManager.prototype = /** @struct */ {
this.getSourceRestriction_())) : this.getSourceRestriction_())) :
null); null);
chrome.fileManagerPrivate.onCrostiniSharedPathsChanged.addListener(
Crostini.onSharedPathsChanged.bind(null, assert(this.volumeManager_)));
this.setupCrostini_(); this.setupCrostini_();
this.ui_.initDirectoryTree(directoryTree); this.ui_.initDirectoryTree(directoryTree);
...@@ -1237,8 +1241,8 @@ FileManager.prototype = /** @struct */ { ...@@ -1237,8 +1241,8 @@ FileManager.prototype = /** @struct */ {
FileManager.prototype.setupCrostini_ = function() { FileManager.prototype.setupCrostini_ = function() {
chrome.fileManagerPrivate.isCrostiniEnabled((crostiniEnabled) => { chrome.fileManagerPrivate.isCrostiniEnabled((crostiniEnabled) => {
// Check for 'crostini-files' feature. // Check for 'crostini-files' feature.
Crostini.IS_CROSTINI_FILES_ENABLED = this.crostini_.setEnabled(
crostiniEnabled && loadTimeData.getBoolean('CROSTINI_FILES_ENABLED'); crostiniEnabled && loadTimeData.getBoolean('CROSTINI_FILES_ENABLED'));
// Setup Linux files fake root. // Setup Linux files fake root.
this.directoryTree.dataModel.linuxFilesItem = crostiniEnabled ? this.directoryTree.dataModel.linuxFilesItem = crostiniEnabled ?
...@@ -1258,7 +1262,7 @@ FileManager.prototype = /** @struct */ { ...@@ -1258,7 +1262,7 @@ FileManager.prototype = /** @struct */ {
// Load any existing shared paths. // Load any existing shared paths.
chrome.fileManagerPrivate.getCrostiniSharedPaths((entries) => { chrome.fileManagerPrivate.getCrostiniSharedPaths((entries) => {
for (let i = 0; i < entries.length; i++) { for (let i = 0; i < entries.length; i++) {
Crostini.registerSharedPath(entries[i], assert(this.volumeManager_)); this.crostini_.registerSharedPath(entries[i]);
} }
}); });
}); });
......
...@@ -1659,7 +1659,7 @@ CommandHandler.COMMANDS_['share-with-linux'] = /** @type {Command} */ ({ ...@@ -1659,7 +1659,7 @@ CommandHandler.COMMANDS_['share-with-linux'] = /** @type {Command} */ ({
'Error sharing with linux: ' + 'Error sharing with linux: ' +
chrome.runtime.lastError.message); chrome.runtime.lastError.message);
} else { } else {
Crostini.registerSharedPath(dir, fileManager.volumeManager); fileManager.crostini.registerSharedPath(dir);
} }
}); });
} }
...@@ -1697,9 +1697,8 @@ CommandHandler.COMMANDS_['share-with-linux'] = /** @type {Command} */ ({ ...@@ -1697,9 +1697,8 @@ CommandHandler.COMMANDS_['share-with-linux'] = /** @type {Command} */ ({
// Must be single directory subfolder of Downloads not already shared. // Must be single directory subfolder of Downloads not already shared.
const entries = CommandUtil.getCommandEntries(event.target); const entries = CommandUtil.getCommandEntries(event.target);
event.canExecute = entries.length === 1 && entries[0].isDirectory && event.canExecute = entries.length === 1 && entries[0].isDirectory &&
!Crostini.isPathShared(entries[0], fileManager.volumeManager) && !fileManager.crostini.isPathShared(entries[0]) &&
Crostini.canSharePath( fileManager.crostini.canSharePath(entries[0], true /* persist */);
entries[0], true /* persist */, fileManager.volumeManager);
event.command.setHidden(!event.canExecute); event.command.setHidden(!event.canExecute);
} }
}); });
...@@ -1724,7 +1723,7 @@ CommandHandler.COMMANDS_['manage-linux-sharing'] = /** @type {Command} */ ({ ...@@ -1724,7 +1723,7 @@ CommandHandler.COMMANDS_['manage-linux-sharing'] = /** @type {Command} */ ({
* @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use. * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
*/ */
canExecute: function(event, fileManager) { canExecute: function(event, fileManager) {
event.canExecute = Crostini.IS_CROSTINI_FILES_ENABLED; event.canExecute = fileManager.crostini.isEnabled();
event.command.setHidden(!event.canExecute); event.command.setHidden(!event.canExecute);
} }
}); });
......
...@@ -15,12 +15,13 @@ ...@@ -15,12 +15,13 @@
* @param {!Array<!chrome.fileManagerPrivate.FileTask>} tasks * @param {!Array<!chrome.fileManagerPrivate.FileTask>} tasks
* @param {chrome.fileManagerPrivate.FileTask} defaultTask * @param {chrome.fileManagerPrivate.FileTask} defaultTask
* @param {!TaskHistory} taskHistory * @param {!TaskHistory} taskHistory
* @param {!Crostini} crostini
* @constructor * @constructor
* @struct * @struct
*/ */
function FileTasks( function FileTasks(
volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes, tasks, volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes, tasks,
defaultTask, taskHistory) { defaultTask, taskHistory, crostini) {
/** /**
* @private {!VolumeManager} * @private {!VolumeManager}
* @const * @const
...@@ -74,6 +75,12 @@ function FileTasks( ...@@ -74,6 +75,12 @@ function FileTasks(
* @const * @const
*/ */
this.taskHistory_ = taskHistory; this.taskHistory_ = taskHistory;
/**
* @private {!Crostini}
* @const
*/
this.crostini_ = crostini;
} }
FileTasks.prototype = { FileTasks.prototype = {
...@@ -155,11 +162,12 @@ FileTasks.TaskPickerType = { ...@@ -155,11 +162,12 @@ FileTasks.TaskPickerType = {
* @param {!Array<!Entry>} entries * @param {!Array<!Entry>} entries
* @param {!Array<?string>} mimeTypes * @param {!Array<?string>} mimeTypes
* @param {!TaskHistory} taskHistory * @param {!TaskHistory} taskHistory
* @param {!Crostini} crostini
* @return {!Promise<!FileTasks>} * @return {!Promise<!FileTasks>}
*/ */
FileTasks.create = function( FileTasks.create = function(
volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes, volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes,
taskHistory) { taskHistory, crostini) {
var tasksPromise = new Promise(function(fulfill) { var tasksPromise = new Promise(function(fulfill) {
// getFileTasks supports only native entries. // getFileTasks supports only native entries.
entries = entries.filter(util.isNativeEntry); entries = entries.filter(util.isNativeEntry);
...@@ -181,9 +189,8 @@ FileTasks.create = function( ...@@ -181,9 +189,8 @@ FileTasks.create = function(
// a dialog with an error message, similar to when attempting to run // a dialog with an error message, similar to when attempting to run
// Crostini tasks with non-Crostini entries. // Crostini tasks with non-Crostini entries.
if (entries.length !== 1 || if (entries.length !== 1 ||
!(Crostini.isCrostiniEntry(entries[0], volumeManager) || !(FileTasks.isCrostiniEntry(entries[0], volumeManager) ||
Crostini.canSharePath( crostini.canSharePath(entries[0], false /* persist */))) {
entries[0], false /* persist */, volumeManager))) {
taskItems = taskItems.filter(function(item) { taskItems = taskItems.filter(function(item) {
var taskParts = item.taskId.split('|'); var taskParts = item.taskId.split('|');
var appId = taskParts[0]; var appId = taskParts[0];
...@@ -213,7 +220,7 @@ FileTasks.create = function( ...@@ -213,7 +220,7 @@ FileTasks.create = function(
return Promise.all([tasksPromise, defaultTaskPromise]).then(function(args) { return Promise.all([tasksPromise, defaultTaskPromise]).then(function(args) {
return new FileTasks( return new FileTasks(
volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes, volumeManager, metadataModel, directoryModel, ui, entries, mimeTypes,
args[0], args[1], taskHistory); args[0], args[1], taskHistory, crostini);
}); });
}; };
...@@ -548,6 +555,28 @@ FileTasks.annotateTasks_ = function(tasks, entries) { ...@@ -548,6 +555,28 @@ FileTasks.annotateTasks_ = function(tasks, entries) {
return result; return result;
}; };
/**
* @param {!Entry} entry
* @param {!VolumeManager} volumeManager
* @return {boolean} True if the entry is from crostini.
*/
FileTasks.isCrostiniEntry = function(entry, volumeManager) {
return volumeManager.getLocationInfo(entry).rootType ===
VolumeManagerCommon.RootType.CROSTINI;
};
/**
* Returns true if task requires entries to be shared before executing task.
* @param {!chrome.fileManagerPrivate.FileTask} task Task to run.
* @return {boolean} true if task requires entries to be shared.
*/
FileTasks.taskRequiresCrostiniSharing = function(task) {
const taskParts = task.taskId.split('|');
const taskType = taskParts[1];
const actionId = taskParts[2];
return taskType === 'crostini' || actionId === 'install-linux-package';
};
/** /**
* Checks if task is a crostini task and all entries are accessible to, or can * Checks if task is a crostini task and all entries are accessible to, or can
* be shared with crostini. Shares files as required if possible and invokes * be shared with crostini. Shares files as required if possible and invokes
...@@ -560,7 +589,7 @@ FileTasks.annotateTasks_ = function(tasks, entries) { ...@@ -560,7 +589,7 @@ FileTasks.annotateTasks_ = function(tasks, entries) {
FileTasks.prototype.maybeShareWithCrostiniOrShowDialog_ = function( FileTasks.prototype.maybeShareWithCrostiniOrShowDialog_ = function(
task, callback) { task, callback) {
// Check if this is a crostini task. // Check if this is a crostini task.
if (!Crostini.taskRequiresSharing(task)) if (!FileTasks.taskRequiresCrostiniSharing(task))
return callback(); return callback();
let showUnableToOpen = false; let showUnableToOpen = false;
...@@ -568,12 +597,11 @@ FileTasks.prototype.maybeShareWithCrostiniOrShowDialog_ = function( ...@@ -568,12 +597,11 @@ FileTasks.prototype.maybeShareWithCrostiniOrShowDialog_ = function(
for (let i = 0; i < this.entries_.length; i++) { for (let i = 0; i < this.entries_.length; i++) {
const entry = this.entries_[i]; const entry = this.entries_[i];
if (Crostini.isCrostiniEntry(entry, this.volumeManager_) || if (FileTasks.isCrostiniEntry(entry, this.volumeManager_) ||
Crostini.isPathShared(entry, this.volumeManager_)) { this.crostini_.isPathShared(entry)) {
continue; continue;
} }
if (!Crostini.canSharePath( if (!this.crostini_.canSharePath(entry, false /* persist */)) {
entry, false /* persist */, this.volumeManager_)) {
showUnableToOpen = true; showUnableToOpen = true;
break; break;
} }
...@@ -613,7 +641,7 @@ FileTasks.prototype.maybeShareWithCrostiniOrShowDialog_ = function( ...@@ -613,7 +641,7 @@ FileTasks.prototype.maybeShareWithCrostiniOrShowDialog_ = function(
} }
// Register paths as shared, and now we are ready to execute. // Register paths as shared, and now we are ready to execute.
entriesToShare.forEach((entry) => { entriesToShare.forEach((entry) => {
Crostini.registerSharedPath(entry, this.volumeManager_); this.crostini_.registerSharedPath(entry);
}); });
callback(); callback();
}); });
...@@ -711,7 +739,7 @@ FileTasks.prototype.executeDefaultInternal_ = function(opt_callback) { ...@@ -711,7 +739,7 @@ FileTasks.prototype.executeDefaultInternal_ = function(opt_callback) {
.create( .create(
this.volumeManager_, this.metadataModel_, this.volumeManager_, this.metadataModel_,
this.directoryModel_, this.ui_, this.entries_, this.directoryModel_, this.ui_, this.entries_,
this.mimeTypes_, this.taskHistory_) this.mimeTypes_, this.taskHistory_, this.crostini_)
.then( .then(
function(tasks) { function(tasks) {
tasks.executeDefault(); tasks.executeDefault();
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
<script src="../../common/js/file_type.js"></script> <script src="../../common/js/file_type.js"></script>
<script src="../../../base/js/test_error_reporting.js"></script> <script src="../../../base/js/test_error_reporting.js"></script>
<script src="../../common/js/util.js"></script> <script src="../../common/js/util.js"></script>
<script src="../../background/js/crostini.js"></script>
<script src="constants.js"></script> <script src="constants.js"></script>
<script src="web_store_utils.js"></script> <script src="web_store_utils.js"></script>
<script src="crostini.js"></script>
<script src="file_tasks.js"></script> <script src="file_tasks.js"></script>
<script src="file_tasks_unittest.js"></script> <script src="file_tasks_unittest.js"></script>
...@@ -15,6 +15,7 @@ var mockTaskHistory = { ...@@ -15,6 +15,7 @@ var mockTaskHistory = {
}; };
loadTimeData.data = { loadTimeData.data = {
DRIVE_FS_ENABLED: false,
MORE_ACTIONS_BUTTON_LABEL: 'MORE_ACTIONS_BUTTON_LABEL', MORE_ACTIONS_BUTTON_LABEL: 'MORE_ACTIONS_BUTTON_LABEL',
NO_TASK_FOR_EXECUTABLE: 'NO_TASK_FOR_EXECUTABLE', NO_TASK_FOR_EXECUTABLE: 'NO_TASK_FOR_EXECUTABLE',
NO_TASK_FOR_FILE_URL: 'NO_TASK_FOR_FILE_URL', NO_TASK_FOR_FILE_URL: 'NO_TASK_FOR_FILE_URL',
...@@ -62,7 +63,7 @@ function setUp() { ...@@ -62,7 +63,7 @@ function setUp() {
* @return {!FileManager} * @return {!FileManager}
*/ */
function getMockFileManager() { function getMockFileManager() {
return { const result = {
volumeManager: { volumeManager: {
getLocationInfo: function(entry) { getLocationInfo: function(entry) {
return {rootType: VolumeManagerCommon.RootType.DRIVE}; return {rootType: VolumeManagerCommon.RootType.DRIVE};
...@@ -77,15 +78,19 @@ function getMockFileManager() { ...@@ -77,15 +78,19 @@ function getMockFileManager() {
} }
}, },
ui: { ui: {
alertDialog: {showHtml: function(title, text, onOk, onCancel, onShow) {}} alertDialog:
{showHtml: function(title, text, onOk, onCancel, onShow) {}}
}, },
metadataModel: {}, metadataModel: {},
directoryModel: { directoryModel: {
getCurrentRootType: function() { getCurrentRootType: function() {
return null; return null;
} }
} },
crostini: new Crostini(),
}; };
result.crostini.init(result.volumeManager);
return result;
} }
/** /**
...@@ -111,7 +116,7 @@ function showHtmlOfAlertDialogIsCalled(entries, expectedTitle, expectedText) { ...@@ -111,7 +116,7 @@ function showHtmlOfAlertDialogIsCalled(entries, expectedTitle, expectedText) {
.create( .create(
fileManager.volumeManager, fileManager.metadataModel, fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, entries, [null], fileManager.directoryModel, fileManager.ui, entries, [null],
mockTaskHistory) mockTaskHistory, fileManager.crostini)
.then(function(tasks) { .then(function(tasks) {
tasks.executeDefault(); tasks.executeDefault();
}); });
...@@ -138,7 +143,7 @@ function openSuggestAppsDialogIsCalled(entries, mimeTypes) { ...@@ -138,7 +143,7 @@ function openSuggestAppsDialogIsCalled(entries, mimeTypes) {
.create( .create(
fileManager.volumeManager, fileManager.metadataModel, fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, entries, mimeTypes, fileManager.directoryModel, fileManager.ui, entries, mimeTypes,
mockTaskHistory) mockTaskHistory, fileManager.crostini)
.then(function(tasks) { .then(function(tasks) {
tasks.executeDefault(); tasks.executeDefault();
}); });
...@@ -166,7 +171,7 @@ function showDefaultTaskDialogCalled(entries, mimeTypes) { ...@@ -166,7 +171,7 @@ function showDefaultTaskDialogCalled(entries, mimeTypes) {
.create( .create(
fileManager.volumeManager, fileManager.metadataModel, fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, entries, mimeTypes, fileManager.directoryModel, fileManager.ui, entries, mimeTypes,
mockTaskHistory) mockTaskHistory, fileManager.crostini)
.then(function(tasks) { .then(function(tasks) {
tasks.executeDefault(); tasks.executeDefault();
}); });
...@@ -231,7 +236,7 @@ function testOpenSuggestAppsDialogWithMetadata(callback) { ...@@ -231,7 +236,7 @@ function testOpenSuggestAppsDialogWithMetadata(callback) {
} }
} }
}, },
[entry], ['application/rtf'], mockTaskHistory) [entry], ['application/rtf'], mockTaskHistory, fileManager.crostini)
.then(function(tasks) { .then(function(tasks) {
tasks.openSuggestAppsDialog( tasks.openSuggestAppsDialog(
function() {}, function() {}, function() {}); function() {}, function() {}, function() {});
...@@ -256,7 +261,7 @@ function testOpenSuggestAppsDialogFailure(callback) { ...@@ -256,7 +261,7 @@ function testOpenSuggestAppsDialogFailure(callback) {
.create( .create(
fileManager.volumeManager, fileManager.metadataModel, fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, [entry], [null], fileManager.directoryModel, fileManager.ui, [entry], [null],
mockTaskHistory) mockTaskHistory, fileManager.crostini)
.then(function(tasks) { .then(function(tasks) {
tasks.openSuggestAppsDialog(function() {}, function() {}, resolve); tasks.openSuggestAppsDialog(function() {}, function() {}, resolve);
}); });
...@@ -361,7 +366,7 @@ function testOpenWithMostRecentlyExecuted(callback) { ...@@ -361,7 +366,7 @@ function testOpenWithMostRecentlyExecuted(callback) {
.create( .create(
fileManager.volumeManager, fileManager.metadataModel, fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, [mockEntry], [null], fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
taskHistory) taskHistory, fileManager.crostini)
.then(function(tasks) { .then(function(tasks) {
tasks.executeDefault(); tasks.executeDefault();
assertEquals(latestTaskId, executedTask); assertEquals(latestTaskId, executedTask);
...@@ -426,7 +431,7 @@ function testOpenZipWithZipArchiver(callback) { ...@@ -426,7 +431,7 @@ function testOpenZipWithZipArchiver(callback) {
.create( .create(
fileManager.volumeManager, fileManager.metadataModel, fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, [mockEntry], [null], fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
taskHistory) taskHistory, fileManager.crostini)
.then(function(tasks) { .then(function(tasks) {
tasks.executeDefault(); tasks.executeDefault();
assertEquals(zipArchiverTaskId, executedTask); assertEquals(zipArchiverTaskId, executedTask);
...@@ -470,7 +475,7 @@ function testOpenInstallLinuxPackageDialog(callback) { ...@@ -470,7 +475,7 @@ function testOpenInstallLinuxPackageDialog(callback) {
.create( .create(
fileManager.volumeManager, fileManager.metadataModel, fileManager.volumeManager, fileManager.metadataModel,
fileManager.directoryModel, fileManager.ui, [mockEntry], [null], fileManager.directoryModel, fileManager.ui, [mockEntry], [null],
mockTaskHistory) mockTaskHistory, fileManager.crostini)
.then(function(tasks) { .then(function(tasks) {
tasks.executeDefault(); tasks.executeDefault();
}); });
...@@ -487,7 +492,11 @@ function testMaybeShareCrostiniOrShowDialog() { ...@@ -487,7 +492,11 @@ function testMaybeShareCrostiniOrShowDialog() {
const mockFsDownloads = new MockFileSystem('downloads'); const mockFsDownloads = new MockFileSystem('downloads');
const sharedDir = new MockDirectoryEntry(mockFsDownloads, '/shared'); const sharedDir = new MockDirectoryEntry(mockFsDownloads, '/shared');
const shared = new MockFileEntry(mockFsDownloads, '/shared/file'); const shared = new MockFileEntry(mockFsDownloads, '/shared/file');
Crostini.registerSharedPath(sharedDir, volumeManagerDownloads);
const crostini = new Crostini();
crostini.init(volumeManagerDownloads);
crostini.setEnabled(true);
crostini.registerSharedPath(sharedDir, volumeManagerDownloads);
const notShared1 = new MockFileEntry(mockFsDownloads, '/notShared/file1'); const notShared1 = new MockFileEntry(mockFsDownloads, '/notShared/file1');
const notShared2 = new MockFileEntry(mockFsDownloads, '/notShared/file2'); const notShared2 = new MockFileEntry(mockFsDownloads, '/notShared/file2');
const otherNotShared = const otherNotShared =
...@@ -510,6 +519,7 @@ function testMaybeShareCrostiniOrShowDialog() { ...@@ -510,6 +519,7 @@ function testMaybeShareCrostiniOrShowDialog() {
} }
const fakeFilesTask = { const fakeFilesTask = {
entries_: entries, entries_: entries,
crostini_: crostini,
ui_: { ui_: {
alertDialog: {showHtml: showHtml}, alertDialog: {showHtml: showHtml},
confirmDialog: {showHtml: showHtml}, confirmDialog: {showHtml: showHtml},
...@@ -530,12 +540,12 @@ function testMaybeShareCrostiniOrShowDialog() { ...@@ -530,12 +540,12 @@ function testMaybeShareCrostiniOrShowDialog() {
expect('No entries', [], true, '', ''); expect('No entries', [], true, '', '');
Crostini.IS_CROSTINI_FILES_ENABLED = false; crostini.setEnabled(false);
expect( expect(
'Single entry, crostini-files not enabled', [notShared1], false, 'Single entry, crostini-files not enabled', [notShared1], false,
'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI'); 'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI');
Crostini.IS_CROSTINI_FILES_ENABLED = true; crostini.setEnabled(true);
expect('Single entry, not shared', [notShared1], true, '', ''); expect('Single entry, not shared', [notShared1], true, '', '');
...@@ -565,3 +575,15 @@ function testMaybeShareCrostiniOrShowDialog() { ...@@ -565,3 +575,15 @@ function testMaybeShareCrostiniOrShowDialog() {
'2 entries, 1 not sharable', [notShared1, unsharable], false, '2 entries, 1 not sharable', [notShared1, unsharable], false,
'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI'); 'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI');
} }
function task(id) {
return /** @type{!chrome.fileManagerPrivate.FileTask} */ ({taskId: id});
}
function testTaskRequiresCrostiniSharing() {
assertTrue(
FileTasks.taskRequiresCrostiniSharing(task('app|crostini|open-with')));
assertTrue(FileTasks.taskRequiresCrostiniSharing(
task('appId|x|install-linux-package')));
assertFalse(FileTasks.taskRequiresCrostiniSharing(task('appId|x|open-with')));
}
...@@ -108,7 +108,6 @@ ...@@ -108,7 +108,6 @@
// <include src="actions_model.js"> // <include src="actions_model.js">
// <include src="app_state_controller.js"> // <include src="app_state_controller.js">
// <include src="column_visibility_controller.js"> // <include src="column_visibility_controller.js">
// <include src="crostini.js">
// <include src="dialog_action_controller.js"> // <include src="dialog_action_controller.js">
// <include src="dialog_type.js"> // <include src="dialog_type.js">
// <include src="directory_contents.js"> // <include src="directory_contents.js">
......
...@@ -10,12 +10,13 @@ ...@@ -10,12 +10,13 @@
* @param {!DirectoryModel} directoryModel * @param {!DirectoryModel} directoryModel
* @param {!FileSelectionHandler} selectionHandler * @param {!FileSelectionHandler} selectionHandler
* @param {!MetadataUpdateController} metadataUpdateController * @param {!MetadataUpdateController} metadataUpdateController
* @param {!Crostini} crostini
* @constructor * @constructor
* @struct * @struct
*/ */
function TaskController( function TaskController(
dialogType, volumeManager, ui, metadataModel, directoryModel, dialogType, volumeManager, ui, metadataModel, directoryModel,
selectionHandler, metadataUpdateController) { selectionHandler, metadataUpdateController, crostini) {
/** /**
* @private {DialogType} * @private {DialogType}
* @const * @const
...@@ -59,6 +60,13 @@ function TaskController( ...@@ -59,6 +60,13 @@ function TaskController(
*/ */
this.metadataUpdateController_ = metadataUpdateController; this.metadataUpdateController_ = metadataUpdateController;
/**
* @type {!Crostini}
* @const
* @private
*/
this.crostini_ = crostini;
/** /**
* @type {!TaskHistory} * @type {!TaskHistory}
* @const * @const
...@@ -376,7 +384,7 @@ TaskController.prototype.getFileTasks = function() { ...@@ -376,7 +384,7 @@ TaskController.prototype.getFileTasks = function() {
.create( .create(
this.volumeManager_, this.metadataModel_, this.directoryModel_, this.volumeManager_, this.metadataModel_, this.directoryModel_,
this.ui_, selection.entries, assert(selection.mimeTypes), this.ui_, selection.entries, assert(selection.mimeTypes),
this.taskHistory_) this.taskHistory_, this.crostini_)
.then(function(tasks) { .then(function(tasks) {
if (this.selectionHandler_.selection !== selection) { if (this.selectionHandler_.selection !== selection) {
if (util.isSameEntries(this.tasksEntries_, selection.entries)) if (util.isSameEntries(this.tasksEntries_, selection.entries))
...@@ -467,7 +475,7 @@ TaskController.prototype.executeEntryTask = function(entry) { ...@@ -467,7 +475,7 @@ TaskController.prototype.executeEntryTask = function(entry) {
.create( .create(
this.volumeManager_, this.metadataModel_, this.directoryModel_, this.volumeManager_, this.metadataModel_, this.directoryModel_,
this.ui_, [entry], [props[0].contentMimeType || null], this.ui_, [entry], [props[0].contentMimeType || null],
this.taskHistory_) this.taskHistory_, this.crostini_)
.then(function(tasks) { .then(function(tasks) {
tasks.executeDefault(); tasks.executeDefault();
}); });
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<script src="../../../base/js/test_error_reporting.js"></script> <script src="../../../base/js/test_error_reporting.js"></script>
<script src="../../common/js/util.js"></script> <script src="../../common/js/util.js"></script>
<script src="../../../base/js/volume_manager_types.js"></script> <script src="../../../base/js/volume_manager_types.js"></script>
<script src="crostini.js"></script> <script src="../../background/js/crostini.js"></script>
<script src="dialog_type.js"></script> <script src="dialog_type.js"></script>
<script src="file_selection.js"></script> <script src="file_selection.js"></script>
<script src="file_tasks.js"></script> <script src="file_tasks.js"></script>
......
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
window.loadTimeData = {
getBoolean: function(key) {
return false;
}
};
window.metrics = { window.metrics = {
recordEnum: function() {} recordEnum: function() {}
}; };
...@@ -31,6 +37,16 @@ function setUp() { ...@@ -31,6 +37,16 @@ function setUp() {
cr.ui.decorate('command', cr.ui.Command); cr.ui.decorate('command', cr.ui.Command);
} }
function createCrostini() {
const crostini = new Crostini();
crostini.init({
getLocationInfo: () => {
return 'test';
}
});
return crostini;
}
function testExecuteEntryTask(callback) { function testExecuteEntryTask(callback) {
window.chrome.fileManagerPrivate = { window.chrome.fileManagerPrivate = {
getFileTasks: function(entries, callback) { getFileTasks: function(entries, callback) {
...@@ -72,7 +88,7 @@ function testExecuteEntryTask(callback) { ...@@ -72,7 +88,7 @@ function testExecuteEntryTask(callback) {
return null; return null;
} }
}, },
new cr.EventTarget(), null); new cr.EventTarget(), null, createCrostini());
controller.executeEntryTask(fileSystem.entries['/test.png']); controller.executeEntryTask(fileSystem.entries['/test.png']);
reportPromise(new Promise(function(fulfill) { reportPromise(new Promise(function(fulfill) {
...@@ -141,7 +157,7 @@ function createTaskController(selectionHandler) { ...@@ -141,7 +157,7 @@ function createTaskController(selectionHandler) {
return null; return null;
} }
}, },
selectionHandler, null); selectionHandler, null, createCrostini());
} }
// TaskController.getFileTasks should not call fileManagerPrivate.getFileTasks // TaskController.getFileTasks should not call fileManagerPrivate.getFileTasks
......
...@@ -57,6 +57,7 @@ js_library("closure_compile_externs") { ...@@ -57,6 +57,7 @@ js_library("closure_compile_externs") {
"$externs_path/metrics_private.js", "$externs_path/metrics_private.js",
"../../externs/app_window_common.js", "../../externs/app_window_common.js",
"../../externs/background/file_browser_background.js", "../../externs/background/file_browser_background.js",
"../../externs/background/crostini.js",
"../../externs/entry_location.js", "../../externs/entry_location.js",
"../../externs/volume_info.js", "../../externs/volume_info.js",
"../../externs/volume_info_list.js", "../../externs/volume_info_list.js",
...@@ -74,7 +75,6 @@ js_library("check_select") { ...@@ -74,7 +75,6 @@ js_library("check_select") {
js_library("crostini_mount") { js_library("crostini_mount") {
deps = [ deps = [
"../foreground/js:crostini",
"js:test_util", "js:test_util",
"//ui/webui/resources/js:webui_resource_test", "//ui/webui/resources/js:webui_resource_test",
] ]
...@@ -82,7 +82,6 @@ js_library("crostini_mount") { ...@@ -82,7 +82,6 @@ js_library("crostini_mount") {
js_library("crostini_share") { js_library("crostini_share") {
deps = [ deps = [
"../foreground/js:crostini",
"js:test_util", "js:test_util",
"//ui/webui/resources/js:webui_resource_test", "//ui/webui/resources/js:webui_resource_test",
] ]
...@@ -90,7 +89,6 @@ js_library("crostini_share") { ...@@ -90,7 +89,6 @@ js_library("crostini_share") {
js_library("crostini_tasks") { js_library("crostini_tasks") {
deps = [ deps = [
"../foreground/js:crostini",
"js:test_util", "js:test_util",
"//ui/webui/resources/js:webui_resource_test", "//ui/webui/resources/js:webui_resource_test",
] ]
......
...@@ -28,11 +28,11 @@ crostiniShare.testSharePathsCrostiniSuccess = (done) => { ...@@ -28,11 +28,11 @@ crostiniShare.testSharePathsCrostiniSuccess = (done) => {
callback(); callback();
}); });
}; };
const oldCrostiniUnregister = Crostini.unregisterSharedPath; const oldCrostiniUnregister = fileManager.crostini.unregisterSharedPath;
let unregisterCalled = false; let unregisterCalled = false;
Crostini.unregisterSharedPath = function(entry, volumeManager) { fileManager.crostini.unregisterSharedPath = function(entry) {
unregisterCalled = true; unregisterCalled = true;
oldCrostiniUnregister(entry, volumeManager); oldCrostiniUnregister.call(fileManager.crostini, entry);
}; };
chrome.metricsPrivate.smallCounts_ = []; chrome.metricsPrivate.smallCounts_ = [];
chrome.metricsPrivate.values_ = []; chrome.metricsPrivate.values_ = [];
...@@ -112,8 +112,8 @@ crostiniShare.testSharePathsCrostiniSuccess = (done) => { ...@@ -112,8 +112,8 @@ crostiniShare.testSharePathsCrostiniSuccess = (done) => {
.then(() => { .then(() => {
// Restore fmp.*. // Restore fmp.*.
chrome.fileManagerPrivate.sharePathsWithCrostini = oldSharePaths; chrome.fileManagerPrivate.sharePathsWithCrostini = oldSharePaths;
// Restore Crostini.unregisterSharedPath; // Restore Crostini.unregisterSharedPath.
Crostini.unregisterSharedPath = oldCrostiniUnregister; fileManager.crostini.unregisterSharedPath = oldCrostiniUnregister;
done(); done();
}); });
}; };
...@@ -159,7 +159,7 @@ crostiniShare.testSharePathShown = (done) => { ...@@ -159,7 +159,7 @@ crostiniShare.testSharePathShown = (done) => {
.getCurrentProfileVolumeInfo( .getCurrentProfileVolumeInfo(
VolumeManagerCommon.VolumeType.DOWNLOADS) VolumeManagerCommon.VolumeType.DOWNLOADS)
.fileSystem.entries['/photos']; .fileSystem.entries['/photos'];
Crostini.registerSharedPath(alreadySharedPhotosDir, mockVolumeManager); fileManager.crostini.registerSharedPath(alreadySharedPhotosDir);
assertTrue( assertTrue(
test.fakeMouseRightClick('#file-list [file-name="photos"]'), test.fakeMouseRightClick('#file-list [file-name="photos"]'),
'right-click hello.txt'); 'right-click hello.txt');
...@@ -252,8 +252,7 @@ crostiniShare.testSharePathShown = (done) => { ...@@ -252,8 +252,7 @@ crostiniShare.testSharePathShown = (done) => {
// Unset DRIVE_FS_ENABLED. // Unset DRIVE_FS_ENABLED.
loadTimeData.data_['DRIVE_FS_ENABLED'] = false; loadTimeData.data_['DRIVE_FS_ENABLED'] = false;
// Clear Crostini shared folders. // Clear Crostini shared folders.
Crostini.unregisterSharedPath( fileManager.crostini.unregisterSharedPath(alreadySharedPhotosDir);
alreadySharedPhotosDir, mockVolumeManager);
done(); done();
}); });
}; };
...@@ -270,13 +269,7 @@ crostiniShare.testGearMenuManageLinuxSharing = (done) => { ...@@ -270,13 +269,7 @@ crostiniShare.testGearMenuManageLinuxSharing = (done) => {
test.setupAndWaitUntilReady() test.setupAndWaitUntilReady()
.then(() => { .then(() => {
// Setup with crostini disabled. // Setup with crostini disabled.
chrome.fileManagerPrivate.crostiniEnabled_ = false; fileManager.crostini.setEnabled(false);
fileManager.setupCrostini_();
return test.repeatUntil(
() => !Crostini.IS_CROSTINI_FILES_ENABLED ||
test.pending('crostini setup'));
})
.then(() => {
// Click gear menu, ensure 'Manage Linux sharing' is hidden. // Click gear menu, ensure 'Manage Linux sharing' is hidden.
assertTrue(test.fakeMouseClick('#gear-button')); assertTrue(test.fakeMouseClick('#gear-button'));
return test.waitForElement(manageLinuxSharingOptionHidden); return test.waitForElement(manageLinuxSharingOptionHidden);
...@@ -288,13 +281,7 @@ crostiniShare.testGearMenuManageLinuxSharing = (done) => { ...@@ -288,13 +281,7 @@ crostiniShare.testGearMenuManageLinuxSharing = (done) => {
}) })
.then(() => { .then(() => {
// Setup with crostini enabled. // Setup with crostini enabled.
chrome.fileManagerPrivate.crostiniEnabled_ = true; fileManager.crostini.setEnabled(true);
fileManager.setupCrostini_();
return test.repeatUntil(
() => Crostini.IS_CROSTINI_FILES_ENABLED ||
test.pending('crostini setup'));
})
.then(() => {
// Click gear menu, ensure 'Manage Linux sharing' is shown. // Click gear menu, ensure 'Manage Linux sharing' is shown.
assertTrue(test.fakeMouseClick('#gear-button')); assertTrue(test.fakeMouseClick('#gear-button'));
return test.waitForElement(manageLinuxSharingOptionShown); return test.waitForElement(manageLinuxSharingOptionShown);
......
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
ChromeEvent.prototype.dispatchEvent = (var_args) => {}; ChromeEvent.prototype.dispatchEvent = (var_args) => {};
/** @constructor */ /** @constructor */
function FileManager() {} function FileManager() {
/** @type {Crostini} */
this.crostini;
}
FileManager.prototype.setupCrostini_ = () => {}; FileManager.prototype.setupCrostini_ = () => {};
/** @type {string} */ /** @type {string} */
......
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