[Files F2] Convert file_manager_base to TS
* Remove file_manager_base extern.
* Remove foreground_window extern, the definition is moved to
file_manager.d.ts which can be recognized by both normal code
and the test code.
* Update all ".then()" style to use async/await.
* Remove unused event check in the event handler.
Bug: b:289003444
Change-Id: Ie78fbc2afd08619a30aceb2e48142c80db65af1f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5076335
Reviewed-by: Luciano Pacheco <lucmult@chromium.org>
Commit-Queue: Wenbo Jie <wenbojie@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1232551}
diff --git a/ui/file_manager/file_manager/background/js/file_manager_base.js b/ui/file_manager/file_manager/background/js/file_manager_base.js
deleted file mode 100644
index c13258b..0000000
--- a/ui/file_manager/file_manager/background/js/file_manager_base.js
+++ /dev/null
@@ -1,433 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-import {assert} from 'chrome://resources/ash/common/assert.js';
-import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
-
-import {resolveIsolatedEntries} from '../../common/js/api.js';
-import {FilesAppState} from '../../common/js/files_app_state.js';
-import {recordInterval} from '../../common/js/metrics.js';
-import {doIfPrimaryContext} from '../../common/js/util.js';
-import {createArchiveOpenedEvent, VOLUME_ALREADY_MOUNTED, VolumeError, VolumeType} from '../../common/js/volume_manager_types.js';
-import {Crostini} from '../../externs/background/crostini.js';
-import {DriveSyncHandler} from '../../externs/background/drive_sync_handler.js';
-import {FileManagerBaseInterface} from '../../externs/background/file_manager_base.js';
-import {ProgressCenter} from '../../externs/background/progress_center.js';
-
-import {CrostiniImpl} from './crostini.js';
-import {DriveSyncHandlerImpl} from './drive_sync_handler.js';
-import {FileOperationHandler} from './file_operation_handler.js';
-import {launchFileManager, setInitializationPromise} from './launcher.js';
-import {ProgressCenterImpl} from './progress_center.js';
-import {volumeManagerFactory} from './volume_manager_factory.js';
-
-/**
- * Root class of the former background page.
- * @implements {FileManagerBaseInterface}
- */
-export class FileManagerBase {
- constructor() {
- /**
- * Map of all currently open file dialogs. The key is an app ID.
- * @type {!Record<string, !Window>}
- */
- this.dialogs = {};
-
- /**
- * Initializes the strings. This needs for the volume manager.
- * @type {?Promise<*>}
- */
- this.initializationPromise_ = new Promise((fulfill) => {
- chrome.fileManagerPrivate.getStrings(stringData => {
- if (chrome.runtime.lastError) {
- console.error(chrome.runtime.lastError.message);
- return;
- }
- if (!loadTimeData.isInitialized()) {
- loadTimeData.data = assert(stringData);
- }
- fulfill(stringData);
- });
- });
-
- /**
- * Progress center of the background page.
- * @type {!ProgressCenter}
- */
- this.progressCenter = new ProgressCenterImpl();
-
- /**
- * Event handler for progress center.
- * @private @type {?FileOperationHandler}
- */
- this.fileOperationHandler_ = null;
-
- /**
- * Drive sync handler.
- * @type {!DriveSyncHandler}
- */
- this.driveSyncHandler = /** @type {!DriveSyncHandler}*/ (
- new DriveSyncHandlerImpl(this.progressCenter));
-
- /** @type {!Crostini} */
- this.crostini = /** @type {!Crostini} */ (new CrostiniImpl());
-
- /**
- * String assets.
- * @type {?Record<string, string>}
- */
- this.stringData = null;
-
- // Initialize string and volume manager related stuffs.
- this.initializationPromise_.then(strings => {
- this.stringData = strings;
- this.crostini.initEnabled();
-
- volumeManagerFactory.getInstance().then(volumeManager => {
- volumeManager.addEventListener(
- VOLUME_ALREADY_MOUNTED, this.handleViewEvent_.bind(this));
-
- this.crostini.initVolumeManager(volumeManager);
- });
-
- this.fileOperationHandler_ =
- new FileOperationHandler(this.progressCenter);
- });
-
- // Handle newly mounted FSP file systems. Workaround for crbug.com/456648.
- // TODO(mtomasz): Replace this hack with a proper solution.
- chrome.fileManagerPrivate.onMountCompleted.addListener(
- this.onMountCompleted_.bind(this));
-
- setInitializationPromise(this.initializationPromise_);
- }
-
- /**
- * @return {!Promise<!import('../../externs/volume_manager.js').VolumeManager>}
- */
- async getVolumeManager() {
- return volumeManagerFactory.getInstance();
- }
-
- /**
- * Register callback to be invoked after initialization.
- * If the initialization is already done, the callback is invoked immediately.
- *
- * @param {function():void} callback Initialize callback to be registered.
- */
- ready(callback) {
- // @ts-ignore: error TS2531: Object is possibly 'null'.
- this.initializationPromise_.then(callback);
- }
-
- /**
- * Registers dialog window to the background page.
- *
- * @param {!Window} dialogWindow Window of the dialog.
- */
- registerDialog(dialogWindow) {
- const id = DIALOG_ID_PREFIX + (nextFileManagerDialogID++);
- this.dialogs[id] = dialogWindow;
- if (window.IN_TEST) {
- dialogWindow.IN_TEST = true;
- }
- dialogWindow.addEventListener('pagehide', () => {
- delete this.dialogs[id];
- });
- }
-
- /**
- * Launches a new File Manager window.
- *
- * @param {!FilesAppState=} appState App state.
- * @return {!Promise<void>} Resolved when the new window is opened.
- */
- // @ts-ignore: error TS2739: Type '{}' is missing the following properties
- // from type 'FilesAppState': currentDirectoryURL, selectionURL
- async launchFileManager(appState = {}) {
- return launchFileManager(appState);
- }
-
- /**
- * Opens the volume root (or opt directoryPath) in main UI.
- *
- * @param {!Event} event An event with the volumeId or
- * devicePath.
- * @private
- */
- handleViewEvent_(event) {
- doIfPrimaryContext(() => {
- this.handleViewEventInternal_(event);
- });
- }
-
- /**
- * @param {!Event} event An event with the volumeId or
- * devicePath.
- * @private
- */
- handleViewEventInternal_(event) {
- volumeManagerFactory.getInstance().then(
- /**
- * Retrieves the root file entry of the volume on the requested
- * device.
- * @param {!import('../../externs/volume_manager.js').VolumeManager}
- * volumeManager
- */
- volumeManager => {
- // @ts-ignore: error TS2339: Property 'devicePath' does not exist on
- // type 'Event'.
- if (event.devicePath) {
- // @ts-ignore: error TS2339: Property 'devicePath' does not exist on
- // type 'Event'.
- const volume = volumeManager.findByDevicePath(event.devicePath);
- if (volume) {
- this.navigateToVolumeRoot_(volume);
- } else {
- console.warn(
- // @ts-ignore: error TS2339: Property 'devicePath' does not
- // exist on type 'Event'.
- `Got view event with invalid volume id: ${event.devicePath}`);
- }
- // @ts-ignore: error TS2339: Property 'volumeId' does not exist on
- // type 'Event'.
- } else if (event.volumeId) {
- if (event.type === VOLUME_ALREADY_MOUNTED) {
- // @ts-ignore: error TS2339: Property 'volumeId' does not exist on
- // type 'Event'.
- this.navigateToVolumeInFocusedWindowWhenReady_(event.volumeId);
- } else {
- // @ts-ignore: error TS2339: Property 'volumeId' does not exist on
- // type 'Event'.
- this.navigateToVolumeWhenReady_(event.volumeId);
- }
- } else {
- console.warn('Got view event with no actionable destination.');
- }
- });
- }
-
- /**
- * Retrieves the root file entry of the volume on the requested device.
- *
- * @param {!string} volumeId ID of the volume to navigate to.
- * @return {!Promise<!import("../../externs/volume_info.js").VolumeInfo>}
- * @private
- */
- retrieveVolumeInfo_(volumeId) {
- // @ts-ignore: error TS2322: Type 'Promise<void | VolumeInfo>' is not
- // assignable to type 'Promise<VolumeInfo>'.
- return volumeManagerFactory.getInstance().then(
- (/**
- * @param {!import('../../externs/volume_manager.js').VolumeManager}
- * volumeManager
- */
- (volumeManager) => {
- return volumeManager.whenVolumeInfoReady(volumeId).catch((e) => {
- console.warn(
- 'Unable to find volume for id: ' + volumeId +
- '. Error: ' + e.message);
- });
- }));
- }
-
- /**
- * Opens the volume root (or opt directoryPath) in main UI.
- *
- * @param {!string} volumeId ID of the volume to navigate to.
- * @param {!string=} opt_directoryPath Optional path to be opened.
- * @private
- */
- navigateToVolumeWhenReady_(volumeId, opt_directoryPath) {
- this.retrieveVolumeInfo_(volumeId).then(volume => {
- this.navigateToVolumeRoot_(volume, opt_directoryPath);
- });
- }
-
- /**
- * Opens the volume root (or opt directoryPath) in the main UI of the focused
- * window.
- *
- * @param {!string} volumeId ID of the volume to navigate to.
- * @param {!string=} opt_directoryPath Optional path to be opened.
- * @private
- */
- navigateToVolumeInFocusedWindowWhenReady_(volumeId, opt_directoryPath) {
- this.retrieveVolumeInfo_(volumeId).then(volume => {
- this.navigateToVolumeInFocusedWindow_(volume, opt_directoryPath);
- });
- }
-
- /**
- * If a path was specified, retrieve that directory entry,
- * otherwise return the root entry of the volume.
- *
- * @param {!import("../../externs/volume_info.js").VolumeInfo} volume
- * @param {string=} opt_directoryPath Optional directory path to be opened.
- * @return {!Promise<!DirectoryEntry>}
- * @private
- */
- retrieveEntryInVolume_(volume, opt_directoryPath) {
- return volume.resolveDisplayRoot().then(root => {
- if (opt_directoryPath) {
- return new Promise(
- root.getDirectory.bind(root, opt_directoryPath, {create: false}));
- } else {
- return Promise.resolve(root);
- }
- });
- }
-
- /**
- * Opens the volume root (or opt directoryPath) in main UI.
- *
- * @param {!import("../../externs/volume_info.js").VolumeInfo} volume
- * @param {string=} opt_directoryPath Optional directory path to be opened.
- * @private
- */
- navigateToVolumeRoot_(volume, opt_directoryPath) {
- this.retrieveEntryInVolume_(volume, opt_directoryPath)
- .then(
- /**
- * Launches app opened on {@code directory}.
- * @param {DirectoryEntry} directory
- */
- directory => {
- // @ts-ignore: error TS2345: Argument of type '{
- // currentDirectoryURL: string; }' is not assignable to parameter
- // of type 'FilesAppState'.
- launchFileManager({currentDirectoryURL: directory.toURL()});
- });
- }
-
- /**
- * Opens the volume root (or opt directoryPath) in main UI of the focused
- * window.
- *
- * @param {!import("../../externs/volume_info.js").VolumeInfo} volume
- * @param {string=} opt_directoryPath Optional directory path to be opened.
- * @private
- */
- navigateToVolumeInFocusedWindow_(volume, opt_directoryPath) {
- this.retrieveEntryInVolume_(volume, opt_directoryPath)
- .then(function(directoryEntry) {
- if (directoryEntry) {
- volumeManagerFactory.getInstance().then(volumeManager => {
- volumeManager.dispatchEvent(
- createArchiveOpenedEvent(directoryEntry));
- });
- }
- });
- }
-
- /**
- * Handles mounted FSP volumes and fires the Files app. This is a quick fix
- * for crbug.com/456648.
- * @param {!Object} event Event details.
- * @private
- */
- onMountCompleted_(event) {
- doIfPrimaryContext(() => {
- this.onMountCompletedInternal_(event);
- });
- }
-
- /**
- * @param {!Object} event Event details.
- * @private
- */
- onMountCompletedInternal_(event) {
- // @ts-ignore: error TS2339: Property 'status' does not exist on type
- // 'Object'.
- const statusOK = event.status === VolumeError.SUCCESS ||
- // @ts-ignore: error TS2339: Property 'status' does not exist on type
- // 'Object'.
- event.status === VolumeError.PATH_ALREADY_MOUNTED;
- const volumeTypeOK =
- // @ts-ignore: error TS2339: Property 'volumeMetadata' does not exist on
- // type 'Object'.
- event.volumeMetadata.volumeType === VolumeType.PROVIDED &&
- // @ts-ignore: error TS2339: Property 'volumeMetadata' does not exist on
- // type 'Object'.
- event.volumeMetadata.source === Source.FILE;
- // @ts-ignore: error TS2339: Property 'eventType' does not exist on type
- // 'Object'.
- if (event.eventType === 'mount' && statusOK &&
- // @ts-ignore: error TS2339: Property 'volumeMetadata' does not exist on
- // type 'Object'.
- event.volumeMetadata.mountContext === 'user' && volumeTypeOK) {
- // @ts-ignore: error TS2339: Property 'volumeMetadata' does not exist on
- // type 'Object'.
- this.navigateToVolumeWhenReady_(event.volumeMetadata.volumeId);
- }
- }
-}
-
-/**
- * @private @type {number} Total number of retries for the resolve entries
- * below.
- */
-const MAX_RETRIES = 6;
-
-/**
- * Retry the resolveIsolatedEntries() until we get the same number of entries
- * back.
- * @param {!Array<!Entry>} isolatedEntries Entries that need to be resolved.
- * @return {!Promise<!Array<!Entry>>} Promise resolved with the entries
- * resolved.
- */
-// @ts-ignore: error TS6133: 'retryResolveIsolatedEntries' is declared but its
-// value is never read.
-async function retryResolveIsolatedEntries(isolatedEntries) {
- let count = 0;
- let externalEntries = [];
- // Wait time in milliseconds between attempts. We double this value after
- // every wait.
- let waitTime = 25;
-
- // Total waiting time is ~1.5 second for `waitTime` starting at 25ms and total
- // of 6 attempts.
- while (count <= MAX_RETRIES) {
- externalEntries = await resolveIsolatedEntries(isolatedEntries);
- if (externalEntries.length >= isolatedEntries.length) {
- return externalEntries;
- }
-
- console.warn(`Failed to resolve, retrying in ${waitTime}ms...`);
- await new Promise(resolve => setTimeout(resolve, waitTime));
- waitTime = waitTime * 2;
- count += 1;
- }
-
- console.warn(
- `Failed to resolve: Requested ${isolatedEntries.length},` +
- ` resolved: ${externalEntries.length}.`);
- return [];
-}
-
-/**
- * Prefix for the dialog ID.
- * @type {!string}
- * @const
- */
-const DIALOG_ID_PREFIX = 'dialog#';
-
-/**
- * Value of the next file manager dialog ID.
- * @type {number}
- */
-let nextFileManagerDialogID = 0;
-
-/**
- * Singleton instance of Background object.
- * @type {!FileManagerBaseInterface}
- */
-export const background = new FileManagerBase();
-// @ts-ignore: error TS2339: Property 'background' does not exist on type
-// 'Window & typeof globalThis'.
-window.background = background;
-
-/**
- * End recording of the background page Load.BackgroundScript metric.
- */
-recordInterval('Load.BackgroundScript');
diff --git a/ui/file_manager/file_manager/background/js/file_manager_base.ts b/ui/file_manager/file_manager/background/js/file_manager_base.ts
new file mode 100644
index 0000000..5dbcd37
--- /dev/null
+++ b/ui/file_manager/file_manager/background/js/file_manager_base.ts
@@ -0,0 +1,293 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
+import {assert} from 'chrome://resources/js/assert.js';
+
+import {getDirectory} from '../../common/js/api.js';
+import {FilesAppState} from '../../common/js/files_app_state.js';
+import {recordInterval} from '../../common/js/metrics.js';
+import {isInGuestMode} from '../../common/js/util.js';
+import {createArchiveOpenedEvent, Source, VOLUME_ALREADY_MOUNTED, VolumeError, VolumeType} from '../../common/js/volume_manager_types.js';
+import {ProgressCenter} from '../../externs/background/progress_center.js';
+import type {VolumeInfo} from '../../externs/volume_info.js';
+import type {VolumeManager} from '../../externs/volume_manager.js';
+
+import {AppWindowWrapper} from './app_window_wrapper.js';
+import {CrostiniImpl} from './crostini.js';
+import {DriveSyncHandlerImpl} from './drive_sync_handler.js';
+import {FileOperationHandler} from './file_operation_handler.js';
+import {ProgressCenterImpl} from './progress_center.js';
+import {volumeManagerFactory} from './volume_manager_factory.js';
+import type {VolumeAlreadyMountedEvent} from './volume_manager_impl.js';
+
+/**
+ * Root class of the former background page.
+ */
+export class FileManagerBase {
+ private initializationPromise_: Promise<Record<string, string>>;
+ protected fileOperationHandler_: FileOperationHandler|null = null;
+
+ /**
+ * Map of all currently open file dialogs. The key is an app ID.
+ */
+ dialogs: Record<string, Window> = {};
+
+ /**
+ * Progress center of the background page.
+ */
+ progressCenter: ProgressCenter = new ProgressCenterImpl();
+
+ /**
+ * Drive sync handler.
+ */
+ driveSyncHandler = new DriveSyncHandlerImpl(this.progressCenter);
+
+ crostini = new CrostiniImpl();
+
+ /**
+ * String assets.
+ */
+ stringData: null|Record<string, string> = null;
+
+ constructor() {
+ /**
+ * Initializes the strings. This needs for the volume manager.
+ */
+ this.initializationPromise_ = new Promise((fulfill) => {
+ chrome.fileManagerPrivate.getStrings(stringData => {
+ if (chrome.runtime.lastError) {
+ console.error(chrome.runtime.lastError.message);
+ return;
+ }
+ if (!loadTimeData.isInitialized()) {
+ loadTimeData.data = assert(stringData);
+ }
+ fulfill(stringData as Record<string, string>);
+ });
+ });
+ this.initializationPromise_.then(strings => {
+ this.stringData = strings;
+ this.crostini.initEnabled();
+
+ volumeManagerFactory.getInstance().then(volumeManager => {
+ volumeManager.addEventListener(
+ VOLUME_ALREADY_MOUNTED, this.handleViewEvent_.bind(this));
+
+ this.crostini.initVolumeManager(volumeManager);
+ });
+
+ this.fileOperationHandler_ =
+ new FileOperationHandler(this.progressCenter);
+ });
+
+ // Handle newly mounted FSP file systems. Workaround for crbug.com/456648.
+ // TODO(mtomasz): Replace this hack with a proper solution.
+ chrome.fileManagerPrivate.onMountCompleted.addListener(
+ this.onMountCompleted_.bind(this));
+ }
+
+ async getVolumeManager(): Promise<VolumeManager> {
+ return volumeManagerFactory.getInstance();
+ }
+
+ async ready(): Promise<void> {
+ await this.initializationPromise_;
+ }
+
+ /**
+ * Registers dialog window to the background page.
+ *
+ * @param dialogWindow Window of the dialog.
+ */
+ registerDialog(dialogWindow: Window) {
+ const id = DIALOG_ID_PREFIX + (nextFileManagerDialogID++);
+ this.dialogs[id] = dialogWindow;
+ if (window.IN_TEST) {
+ dialogWindow.IN_TEST = true;
+ }
+ dialogWindow.addEventListener('pagehide', () => {
+ delete this.dialogs[id];
+ });
+ }
+
+ /**
+ * Launches a new File Manager window.
+ *
+ * @param appState App state.
+ * @return Resolved when the new window is opened.
+ */
+ async launchFileManager(appState: FilesAppState = {}): Promise<void> {
+ await this.initializationPromise_;
+
+ const appWindow = new AppWindowWrapper();
+
+ return appWindow.launch(appState || {});
+ }
+
+ /**
+ * Opens the volume root (or opt directoryPath) in main UI.
+ *
+ * @param event An event with the volumeId or
+ * devicePath.
+ */
+ private async handleViewEvent_(event: Event) {
+ const isPrimaryContext = await isInGuestMode();
+ if (isPrimaryContext) {
+ this.handleViewEventInternal_(event);
+ }
+ }
+
+ /**
+ * @param event An event with the volumeId.
+ */
+ private async handleViewEventInternal_(event: Event): Promise<void> {
+ await volumeManagerFactory.getInstance();
+ // event can only be VolumeAlreadyMountedEvent according to the
+ // addEventListener in the constructor.
+ const volumeAlreadyMountedEvent = event as VolumeAlreadyMountedEvent;
+ this.navigateToVolumeInFocusedWindowWhenReady_(
+ volumeAlreadyMountedEvent.volumeId);
+ }
+
+ /**
+ * Retrieves the root file entry of the volume on the requested device.
+ *
+ * @param volumeId ID of the volume to navigate to.
+ */
+ private async retrieveVolumeInfo_(volumeId: string):
+ Promise<VolumeInfo|void> {
+ const volumeManager = await volumeManagerFactory.getInstance();
+ try {
+ return await volumeManager.whenVolumeInfoReady(volumeId);
+ } catch (e: any) {
+ console.warn(
+ 'Unable to find volume for id: ' + volumeId +
+ '. Error: ' + e.message);
+ }
+ }
+
+ /**
+ * Opens the volume root (or opt directoryPath) in main UI.
+ *
+ * @param volumeId ID of the volume to navigate to.
+ * @param directoryPath Optional path to be opened.
+ */
+ private async navigateToVolumeWhenReady_(
+ volumeId: string, directoryPath?: string): Promise<void> {
+ const volume = await this.retrieveVolumeInfo_(volumeId);
+ if (volume) {
+ this.navigateToVolumeRoot_(volume, directoryPath);
+ }
+ }
+
+ /**
+ * Opens the volume root (or opt directoryPath) in the main UI of the focused
+ * window.
+ *
+ * @param volumeId ID of the volume to navigate to.
+ * @param directoryPath Optional path to be opened.
+ */
+ private async navigateToVolumeInFocusedWindowWhenReady_(
+ volumeId: string, directoryPath?: string): Promise<void> {
+ const volume = await this.retrieveVolumeInfo_(volumeId);
+ if (volume) {
+ this.navigateToVolumeInFocusedWindow_(volume, directoryPath);
+ }
+ }
+
+ /**
+ * If a path was specified, retrieve that directory entry,
+ * otherwise return the root entry of the volume.
+ *
+ * @param directoryPath Optional directory path to be opened.
+ */
+ private async retrieveEntryInVolume_(
+ volume: VolumeInfo, directoryPath?: string): Promise<DirectoryEntry> {
+ const root = await volume.resolveDisplayRoot();
+ if (directoryPath) {
+ return getDirectory(root, directoryPath, {create: false});
+ }
+ return root;
+ }
+
+ /**
+ * Opens the volume root (or opt directoryPath) in main UI.
+ *
+ * @param directoryPath Optional directory path to be opened.
+ */
+ private async navigateToVolumeRoot_(
+ volume: VolumeInfo, directoryPath?: string): Promise<void> {
+ const directory = await this.retrieveEntryInVolume_(volume, directoryPath);
+ /**
+ * Launches app opened on {@code directory}.
+ */
+ this.launchFileManager({currentDirectoryURL: directory.toURL()});
+ }
+
+ /**
+ * Opens the volume root (or opt directoryPath) in main UI of the focused
+ * window.
+ *
+ * @param directoryPath Optional directory path to be opened.
+ */
+ private async navigateToVolumeInFocusedWindow_(
+ volume: VolumeInfo, directoryPath?: string): Promise<void> {
+ const directoryEntry =
+ await this.retrieveEntryInVolume_(volume, directoryPath);
+ if (directoryEntry) {
+ const volumeManager = await volumeManagerFactory.getInstance();
+ volumeManager.dispatchEvent(createArchiveOpenedEvent(directoryEntry));
+ }
+ }
+
+ /**
+ * Handles mounted FSP volumes and fires the Files app. This is a quick fix
+ * for crbug.com/456648.
+ * @param event Event details.
+ */
+ private async onMountCompleted_(
+ event: chrome.fileManagerPrivate.MountCompletedEvent) {
+ const isPrimaryContext = await isInGuestMode();
+ if (isPrimaryContext) {
+ this.onMountCompletedInternal_(event);
+ }
+ }
+
+ /**
+ * @param event Event details.
+ */
+ private onMountCompletedInternal_(
+ event: chrome.fileManagerPrivate.MountCompletedEvent) {
+ const statusOK = event.status === VolumeError.SUCCESS ||
+ event.status === VolumeError.PATH_ALREADY_MOUNTED;
+ const volumeTypeOK =
+ event.volumeMetadata.volumeType === VolumeType.PROVIDED &&
+ event.volumeMetadata.source === Source.FILE;
+ if (event.eventType === 'mount' && statusOK &&
+ event.volumeMetadata.mountContext === 'user' && volumeTypeOK) {
+ this.navigateToVolumeWhenReady_(event.volumeMetadata.volumeId);
+ }
+ }
+}
+
+/**
+ * Prefix for the dialog ID.
+ */
+const DIALOG_ID_PREFIX = 'dialog#';
+
+/**
+ * Value of the next file manager dialog ID.
+ */
+let nextFileManagerDialogID = 0;
+
+/**
+ * Singleton instance of Background object.
+ */
+export const background = new FileManagerBase();
+window.background = background;
+
+/**
+ * End recording of the background page Load.BackgroundScript metric.
+ */
+recordInterval('Load.BackgroundScript');
diff --git a/ui/file_manager/file_manager/background/js/launcher.ts b/ui/file_manager/file_manager/background/js/launcher.ts
deleted file mode 100644
index 1f4ec6d..0000000
--- a/ui/file_manager/file_manager/background/js/launcher.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import type {FilesAppState} from '../../common/js/files_app_state.js';
-
-import {AppWindowWrapper} from './app_window_wrapper.js';
-
-/**
- * Prefix for the file manager window ID.
- */
-const FILES_ID_PREFIX = 'files#';
-
-/**
- * Regexp matching a file manager window ID.
- */
-export const FILES_ID_PATTERN = new RegExp('^' + FILES_ID_PREFIX + '(\\d*)$');
-
-/**
- * Promise to serialize asynchronous calls.
- */
-let initializationPromise: Promise<void>|null = null;
-
-export function setInitializationPromise(promise: Promise<void>) {
- initializationPromise = promise;
-}
-
-/**
- * The returned promise will be resolved when the window is launched.
- */
-export async function launchFileManager(appState?: FilesAppState):
- Promise<void> {
- // Serialize concurrent calls to launchFileManager.
- if (!initializationPromise) {
- throw new Error('Missing initializationPromise');
- }
-
- await initializationPromise;
-
- const appWindow = new AppWindowWrapper();
-
- // TODO: Remove `as FileAppsState` this type is an TS interface.
- await appWindow.launch(appState || {} as FilesAppState);
-}
diff --git a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
index e0bf997..c42f1ea8 100644
--- a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
+++ b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
@@ -14,16 +14,9 @@
import {entriesToURLs} from '../../common/js/entry_utils.js';
import {recordEnum} from '../../common/js/metrics.js';
import {VolumeType} from '../../common/js/volume_manager_types.js';
-import {FileManagerBaseInterface} from '../../externs/background/file_manager_base.js';
import {test} from './test_util_base.js';
-
-/** @type {!FileManagerBaseInterface} */
-// @ts-ignore: error TS2339: Property 'background' does not exist on type
-// 'Window & typeof globalThis'.
-window.background;
-
/**
* @typedef {{
* attributes:Record<string, string>,
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.ts b/ui/file_manager/file_manager/background/js/volume_manager_impl.ts
index cd086454..20fe50f 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_impl.ts
+++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.ts
@@ -153,7 +153,7 @@
}
-type VolumeAlreadyMountedEvent = Event&{
+export type VolumeAlreadyMountedEvent = Event&{
volumeId: string,
};
diff --git a/ui/file_manager/file_manager/common/js/files_app_state.ts b/ui/file_manager/file_manager/common/js/files_app_state.ts
index 3571d667..03edf27 100644
--- a/ui/file_manager/file_manager/common/js/files_app_state.ts
+++ b/ui/file_manager/file_manager/common/js/files_app_state.ts
@@ -32,31 +32,31 @@
/**
* The desired target directory when opening a new window.
*/
- currentDirectoryURL: string|null|undefined;
+ currentDirectoryURL?: string|null;
/**
* The URL for a file or directory to be selected once a new window is
* spawned.
*/
- selectionURL: string|undefined;
+ selectionURL?: string;
/**
* For SaveAs dialog it prefills the <input> for the file name with this
* value.
* For FilePicker it pre-selects the file in the file list.
*/
- targetName: string|undefined;
+ targetName?: string;
/**
* Search term to initialize the Files app directly in a search results.
*/
- searchQuery: string|undefined;
+ searchQuery?: string;
/**
* The type of the window being opened, when it's undefined it defaults to
* the normal Files app window (non-dialog version).
*/
- type: DialogType|undefined;
+ type?: DialogType;
/**
* List of file extensions (.txt, .zip, etc) that will be used by
@@ -64,13 +64,13 @@
* Files app displays Android apps that can handle such extensions in the
* DirectoryTree.
*/
- typeList: TypeList[]|undefined;
+ typeList?: TypeList[];
/**
* For FilePicker indicates that the "All files" should be displayed in the
* file type dropdown in the footer.
*/
- includeAllFiles: boolean|undefined;
+ includeAllFiles?: boolean;
/**
* Defines what volumes are available in the Files app, when NATIVE_PATH is
@@ -78,12 +78,12 @@
*
* Defaults to `ANY_PATH_OR_URL` when undefined.
*/
- allowedPaths: AllowedPaths|undefined;
+ allowedPaths?: AllowedPaths;
/**
* If the Android apps should be shown in the DirectoryTree for FilePicker.
*/
- showAndroidPickerApps: boolean|undefined;
+ showAndroidPickerApps?: boolean;
/**
* Array of Files app mode dependent volume filter names. Defaults to an
@@ -92,5 +92,5 @@
* See filtered_volume_manager.js for details about the available volume
* filter names and their volume filter effects.
*/
- volumeFilter: string[]|undefined;
+ volumeFilter?: string[];
}
diff --git a/ui/file_manager/file_manager/common/js/util.ts b/ui/file_manager/file_manager/common/js/util.ts
index 4910ccf5..6fced3c 100644
--- a/ui/file_manager/file_manager/common/js/util.ts
+++ b/ui/file_manager/file_manager/common/js/util.ts
@@ -171,21 +171,6 @@
}
/**
- * Executes a functions only when the context is not the incognito one in a
- * regular session. Returns a promise that when fulfilled informs us whether or
- * not the callback was invoked.
- */
-export async function doIfPrimaryContext(callback: VoidCallback):
- Promise<boolean> {
- const guestMode = await isInGuestMode();
- if (guestMode) {
- callback();
- return true;
- }
- return false;
-}
-
-/**
* Returns the Files app modal dialog used to embed any files app dialog
* that derives from cr.ui.dialogs.
*/
diff --git a/ui/file_manager/file_manager/definitions/file_manager.d.ts b/ui/file_manager/file_manager/definitions/file_manager.d.ts
index de069fb8..5b93f60f 100644
--- a/ui/file_manager/file_manager/definitions/file_manager.d.ts
+++ b/ui/file_manager/file_manager/definitions/file_manager.d.ts
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import type {FileManagerBase} from '../background/js/file_manager_base.js';
import type {VolumeManager} from '../externs/volume_manager.js';
-import {MetadataModel} from '../foreground/js/metadata/metadata_model.js';
+import type {MetadataModel} from '../foreground/js/metadata/metadata_model.js';
/**
* Type definition for foreground/js/file_manager.js:FileManager.
@@ -55,6 +56,9 @@
},
};
+ // Defined in the file_manager_base.ts
+ background: FileManagerBase;
+
// Defined in the main_window_component.ts
isFocused?: () => boolean;
}
diff --git a/ui/file_manager/file_manager/externs/background/file_manager_base.js b/ui/file_manager/file_manager/externs/background/file_manager_base.js
deleted file mode 100644
index f10f18c9..0000000
--- a/ui/file_manager/file_manager/externs/background/file_manager_base.js
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {FilesAppState} from '../../common/js/files_app_state.js';
-
-import {Crostini} from './crostini.js';
-import {DriveSyncHandler} from './drive_sync_handler.js';
-import {ProgressCenter} from './progress_center.js';
-
-/**
- * @interface
- */
-export class FileManagerBaseInterface {
- constructor() {
- /** @type {!Record<string, !Window>} */
- this.dialogs;
-
- /**
- * @type {!DriveSyncHandler}
- */
- this.driveSyncHandler;
-
- /**
- * @type {!ProgressCenter}
- */
- this.progressCenter;
-
- /**
- * String assets.
- * @type {?Record<string, string>}
- */
- this.stringData;
-
- /**
- * @type {!Crostini}
- */
- this.crostini;
- }
-
- // @ts-ignore: error TS2355: A function whose declared type is neither 'void'
- // nor 'any' must return a value.
- /** @return {!Promise<!import('../volume_manager.js').VolumeManager>} */
- getVolumeManager() {}
-
- /**
- * Register callback to be invoked after initialization of the background
- * page. If the initialization is already done, the callback is invoked
- * immediately.
- *
- * @param {function():void} callback
- */
- // @ts-ignore: error TS6133: 'callback' is declared but its value is never
- // read.
- ready(callback) {}
-
- /**
- * Registers a dialog (file picker or save as) in the background page.
- * Dialogs are opened by the browser directly and should register themselves
- * in the background page.
- * @param {!Window} window
- */
- // @ts-ignore: error TS6133: 'window' is declared but its value is never read.
- registerDialog(window) {}
-
- /**
- * Launches a new File Manager window.
- *
- * @param {!FilesAppState=} appState App state.
- * @return {!Promise<void>} Resolved when the new window is opened.
- */
- // @ts-ignore: error TS2739: Type '{}' is missing the following properties
- // from type 'FilesAppState': currentDirectoryURL, selectionURL
- async launchFileManager(appState = {}) {}
-}
diff --git a/ui/file_manager/file_manager/externs/foreground_window.js b/ui/file_manager/file_manager/externs/foreground_window.js
deleted file mode 100644
index 46fc169d..0000000
--- a/ui/file_manager/file_manager/externs/foreground_window.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview External objects and functions required for compiling tests.
- */
-
-import {Crostini} from './background/crostini.js';
-import {FileManagerBaseInterface} from './background/file_manager_base.js';
-
-/** @interface */
-class FileManagerTestDeps {
- constructor() {
- /** @type {Crostini} */
- this.crostini;
- }
-}
-
-/**
- * @extends {Window}
- */
-export class ForegroundWindow {
- constructor() {
- /** @type {FileManagerTestDeps} */
- this.fileManager;
-
- /**
- * @type {!FileManagerBaseInterface}
- */
- this.background;
- }
-
- // @ts-ignore: error TS2355: A function whose declared type is neither 'void'
- // nor 'any' must return a value.
- /** @return {boolean} */
- isFocused() {}
-}
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index d1074dd..b44658b 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -18,6 +18,7 @@
import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js';
import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
+import {FileManagerBase} from '../../background/js/file_manager_base.js';
import {getBulkPinProgress, getDialogCaller, getDlpBlockedComponents, getDriveConnectionState, getPreferences} from '../../common/js/api.js';
import {ArrayDataModel} from '../../common/js/array_data_model.js';
import {isFolderDialogType} from '../../common/js/dialog_type.js';
@@ -35,11 +36,9 @@
import {DirectoryTreeContainer} from '../../containers/directory_tree_container.js';
import {NudgeType} from '../../containers/nudge_container.js';
import {Crostini} from '../../externs/background/crostini.js';
-import {FileManagerBaseInterface} from '../../externs/background/file_manager_base.js';
import {ProgressCenter} from '../../externs/background/progress_center.js';
import {CommandHandlerDeps} from '../../externs/command_handler_deps.js';
import {FakeEntry, FilesAppDirEntry} from '../../externs/files_app_entry_interfaces.js';
-import {ForegroundWindow} from '../../externs/foreground_window.js';
import {DialogType, PropStatus, SearchLocation} from '../../externs/ts/state.js';
import {Store} from '../../externs/ts/store.js';
import {getMyFiles} from '../../state/ducks/all_entries.js';
@@ -344,7 +343,7 @@
// DOM elements.
/**
- * @private @type {?FileManagerBaseInterface}
+ * @private @type {?FileManagerBase}
*/
this.fileBrowserBackground_ = null;
@@ -1097,16 +1096,9 @@
async startInitBackgroundPage_() {
startInterval('Load.InitBackgroundPage');
- this.fileBrowserBackground_ =
- // @ts-ignore: error TS2352: Conversion of type 'Window & typeof
- // globalThis' to type 'ForegroundWindow' may be a mistake because
- // neither type sufficiently overlaps with the other. If this was
- // intentional, convert the expression to 'unknown' first.
- /** @type {!ForegroundWindow} */ (window).background;
+ this.fileBrowserBackground_ = window.background;
- // @ts-ignore: error TS2345: Argument of type '(value: any) => void' is not
- // assignable to parameter of type '() => void'.
- await new Promise(resolve => this.fileBrowserBackground_.ready(resolve));
+ await this.fileBrowserBackground_.ready();
// For the SWA, we load background and foreground in the same Window, avoid
// loading the `data` twice.
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni
index 7394a3a..e56bfdc 100644
--- a/ui/file_manager/file_names.gni
+++ b/ui/file_manager/file_names.gni
@@ -15,8 +15,6 @@
static_js_files = [
# Background:
- "file_manager/background/js/file_manager_base.js",
-
"file_manager/background/js/runtime_loaded_test_util.js",
"file_manager/background/js/test_util.js",
@@ -31,13 +29,11 @@
# Externs:
"file_manager/externs/background/crostini.js",
"file_manager/externs/background/drive_sync_handler.js",
- "file_manager/externs/background/file_manager_base.js",
"file_manager/externs/background/progress_center.js",
"file_manager/externs/command_handler_deps.js",
"file_manager/externs/entry_location.js",
"file_manager/externs/exif_entry.js",
"file_manager/externs/files_app_entry_interfaces.js",
- "file_manager/externs/foreground_window.js",
"file_manager/externs/metadata_model.js",
"file_manager/externs/progress_center_panel.js",
"file_manager/externs/volume_info_list.js",
@@ -285,9 +281,9 @@
"file_manager/background/js/drive_sync_handler.ts",
"file_manager/background/js/entry_location_impl.ts",
"file_manager/foreground/js/file_selection.ts",
+ "file_manager/background/js/file_manager_base.ts",
"file_manager/background/js/file_operation_handler.ts",
"file_manager/foreground/js/file_watcher.ts",
- "file_manager/background/js/launcher.ts",
"file_manager/foreground/js/main_window_component.ts",
"file_manager/background/js/metrics_start.ts",
"file_manager/foreground/js/mock_actions_model.ts",