Commit 99908d51 authored by Austin Tankiang's avatar Austin Tankiang Committed by Commit Bot

Migrate format notifications to visual signals

Bug: 988586
Change-Id: Ia2868d3a7ccdda994c1bfddd123e78d46f72e934
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1978337Reviewed-by: default avatarAlex Danilo <adanilo@chromium.org>
Reviewed-by: default avatarNoel Gordon <noel@chromium.org>
Commit-Queue: Austin Tankiang <austinct@chromium.org>
Cr-Commit-Position: refs/heads/master@{#727339}
parent 6b419012
......@@ -555,6 +555,10 @@ std::unique_ptr<base::DictionaryValue> GetFileManagerStrings() {
IDS_FILE_BROWSER_FORMAT_DIALOG_FORMAT_LABEL);
SET_STRING("FORMAT_DIALOG_CONFIRM_LABEL",
IDS_FILE_BROWSER_FORMAT_DIALOG_CONFIRM_LABEL);
SET_STRING("FORMAT_PROGRESS_MESSAGE",
IDS_FILE_BROWSER_FORMAT_PROGRESS_MESSAGE);
SET_STRING("FORMAT_SUCCESS_MESSAGE", IDS_FILE_BROWSER_FORMAT_SUCCESS_MESSAGE);
SET_STRING("FORMAT_FAILURE_MESSAGE", IDS_FILE_BROWSER_FORMAT_FAILURE_MESSAGE);
SET_STRING("SHARE_BUTTON_TOOLTIP", IDS_FILE_BROWSER_SHARE_BUTTON_TOOLTIP);
SET_STRING("SORT_BUTTON_TOOLTIP", IDS_FILE_BROWSER_SORT_BUTTON_TOOLTIP);
SET_STRING("GEAR_BUTTON_TOOLTIP", IDS_FILE_BROWSER_GEAR_BUTTON_TOOLTIP);
......
......@@ -913,6 +913,16 @@
Erase and Format
</message>
<message name="IDS_FILE_BROWSER_FORMAT_PROGRESS_MESSAGE" desc="Notification message displayed while formatting an external drive">
Formatting <ph name="DRIVE_NAME">$1<ex>My USB</ex></ph>...
</message>
<message name="IDS_FILE_BROWSER_FORMAT_SUCCESS_MESSAGE" desc="Notification message displayed when formatting of an external drive has succeeded">
Formatted <ph name="DRIVE_NAME">$1<ex>My USB</ex></ph>
</message>
<message name="IDS_FILE_BROWSER_FORMAT_FAILURE_MESSAGE" desc="Notification message displayed if formatting of an external drive has failed">
Could not format <ph name="DRIVE_NAME">$1<ex>My USB</ex></ph>
</message>
<message name="IDS_FILE_BROWSER_SUGGEST_DIALOG_TITLE" desc="Title of the suggest app dialog, which shows the list of the apps which supports the selected file.">
Select an app to open this file
</message>
......
3f513edddc965117bc53f0c5f57d5b5d39417fea
\ No newline at end of file
795c542fbd79365530657f9345656fa2c84bfcc2
\ No newline at end of file
ea2c280af3fb9e06ded0a6a4b80b075723027811
\ No newline at end of file
......@@ -178,9 +178,11 @@ js_unittest("crostini_unittest") {
js_library("device_handler") {
deps = [
":progress_center",
":volume_manager_factory",
"//ui/file_manager/file_manager/common/js:async_util",
"//ui/file_manager/file_manager/common/js:importer_common",
"//ui/file_manager/file_manager/common/js:progress_center_common",
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js/cr:event_target",
]
......@@ -189,6 +191,7 @@ js_library("device_handler") {
js_unittest("device_handler_unittest") {
deps = [
":device_handler",
":mock_progress_center",
":mock_volume_manager",
"//ui/file_manager/base/js:mock_chrome",
"//ui/file_manager/base/js:test_error_reporting",
......
......@@ -42,7 +42,7 @@ class FileBrowserBackgroundImpl extends BackgroundBase {
* Event handler for C++ sides notifications.
* @private {!DeviceHandler}
*/
this.deviceHandler_ = new DeviceHandler();
this.deviceHandler_ = new DeviceHandler(this.progressCenter);
// Handle device navigation requests.
this.deviceHandler_.addEventListener(
......@@ -169,7 +169,7 @@ class FileBrowserBackgroundImpl extends BackgroundBase {
*/
volumeManager => {
if (event.devicePath) {
let volume = volumeManager.findByDevicePath(event.devicePath);
const volume = volumeManager.findByDevicePath(event.devicePath);
if (volume) {
this.navigateToVolumeRoot_(volume, event.filePath);
} else {
......@@ -330,7 +330,7 @@ class FileBrowserBackgroundImpl extends BackgroundBase {
}
});
}
let appState = {};
const appState = {};
let launchType = LaunchType.FOCUS_ANY_OR_CREATE;
if (urls) {
appState.selectionURL = urls[0];
......@@ -456,9 +456,9 @@ class FileBrowserBackgroundImpl extends BackgroundBase {
// mounted volume.
this.findFocusedWindow_()
.then(key => {
let statusOK = event.status === 'success' ||
const statusOK = event.status === 'success' ||
event.status === 'error_path_already_mounted';
let volumeTypeOK = event.volumeMetadata.volumeType ===
const volumeTypeOK = event.volumeMetadata.volumeType ===
VolumeManagerCommon.VolumeType.PROVIDED &&
event.volumeMetadata.source === VolumeManagerCommon.Source.FILE;
if (key === null && event.eventType === 'mount' && statusOK &&
......
......@@ -4,9 +4,18 @@
/** Handler of device event. */
class DeviceHandler extends cr.EventTarget {
constructor() {
/** @param {!ProgressCenter} progressCenter */
constructor(progressCenter) {
super();
/**
* Progress center to notify for format events.
* @type {!ProgressCenter}
* @const
* @private
*/
this.progressCenter_ = progressCenter;
/**
* Map of device path and mount status of devices.
* @private {Object<DeviceHandler.MountStatus>}
......@@ -54,15 +63,9 @@ class DeviceHandler extends cr.EventTarget {
DeviceHandler.Notification.DEVICE_HARD_UNPLUGGED.show(event.devicePath);
break;
case 'format_start':
DeviceHandler.Notification.FORMAT_START.show(event.devicePath);
break;
case 'format_success':
DeviceHandler.Notification.FORMAT_START.hide(event.devicePath);
DeviceHandler.Notification.FORMAT_SUCCESS.show(event.devicePath);
break;
case 'format_fail':
DeviceHandler.Notification.FORMAT_START.hide(event.devicePath);
DeviceHandler.Notification.FORMAT_FAIL.show(event.devicePath);
this.handleFormatEvent_(event);
break;
case 'rename_fail':
DeviceHandler.Notification.RENAME_FAIL.show(event.devicePath);
......@@ -73,6 +76,51 @@ class DeviceHandler extends cr.EventTarget {
}
}
/**
* Handles format events and displays a notification in the progress center.
* @param {chrome.fileManagerPrivate.DeviceEvent} event Device event.
* @private
*/
handleFormatEvent_(event) {
const item = new ProgressCenterItem();
item.id = 'format:' + event.devicePath;
item.type = ProgressItemType.FORMAT;
item.itemCount = 1;
item.progressMax = 1;
let notificationType;
switch (event.type) {
case 'format_start':
item.state = ProgressItemState.PROGRESSING;
item.message = strf('FORMAT_PROGRESS_MESSAGE', event.deviceLabel);
item.progressValue = 0;
notificationType = DeviceHandler.Notification.Type.FORMAT_START;
break;
case 'format_success':
item.state = ProgressItemState.COMPLETED;
item.message = strf('FORMAT_SUCCESS_MESSAGE', event.deviceLabel);
item.progressValue = 1;
notificationType = DeviceHandler.Notification.Type.FORMAT_SUCCESS;
break;
case 'format_fail':
item.state = ProgressItemState.ERROR;
item.message = strf('FORMAT_FAILURE_MESSAGE', event.deviceLabel);
item.progressValue = 0;
notificationType = DeviceHandler.Notification.Type.FORMAT_FAIL;
break;
default:
console.error('Unknown format event type: ' + event.type);
break;
}
this.progressCenter_.updateItem(item);
requestIdleCallback(
() => metrics.recordEnum(
'Notification.Show', notificationType,
DeviceHandler.Notification.TypesForUMA));
}
/**
* Handles mount completed events to show notifications for removable devices.
* @param {chrome.fileManagerPrivate.MountCompletedEvent} event Mount
......@@ -747,32 +795,6 @@ DeviceHandler.Notification.DEVICE_HARD_UNPLUGGED =
DeviceHandler.Notification.Type.DEVICE_HARD_UNPLUGGED, 'hardUnplugged',
'DEVICE_HARD_UNPLUGGED_TITLE', 'DEVICE_HARD_UNPLUGGED_MESSAGE');
/**
* @type {DeviceHandler.Notification}
* @const
*/
DeviceHandler.Notification.FORMAT_START = new DeviceHandler.Notification(
DeviceHandler.Notification.Type.FORMAT_START, 'formatStart',
'FORMATTING_OF_DEVICE_PENDING_TITLE',
'FORMATTING_OF_DEVICE_PENDING_MESSAGE');
/**
* @type {DeviceHandler.Notification}
* @const
*/
DeviceHandler.Notification.FORMAT_SUCCESS = new DeviceHandler.Notification(
DeviceHandler.Notification.Type.FORMAT_SUCCESS, 'formatSuccess',
'FORMATTING_OF_DEVICE_FINISHED_TITLE',
'FORMATTING_FINISHED_SUCCESS_MESSAGE');
/**
* @type {DeviceHandler.Notification}
* @const
*/
DeviceHandler.Notification.FORMAT_FAIL = new DeviceHandler.Notification(
DeviceHandler.Notification.Type.FORMAT_FAIL, 'formatFail',
'FORMATTING_OF_DEVICE_FAILED_TITLE', 'FORMATTING_FINISHED_FAILURE_MESSAGE');
/**
* @type {DeviceHandler.Notification}
* @const
......
......@@ -6,6 +6,9 @@
/** @type {!MockVolumeManager} */
let volumeManager;
/** @type {!MockProgressCenter} */
let progressCenter;
/** @type {!DeviceHandler} */
let deviceHandler;
......@@ -27,6 +30,9 @@ function setUp() {
DEVICE_UNSUPPORTED_MESSAGE: 'DEVICE_UNSUPPORTED: $1',
DEVICE_UNKNOWN_MESSAGE: 'DEVICE_UNKNOWN: $1',
MULTIPART_DEVICE_UNSUPPORTED_MESSAGE: 'MULTIPART_DEVICE_UNSUPPORTED: $1',
FORMAT_PROGRESS_MESSAGE: 'FORMAT_PROGRESS_MESSAGE: $1',
FORMAT_SUCCESS_MESSAGE: 'FORMAT_SUCCESS_MESSAGE: $1',
FORMAT_FAILURE_MESSAGE: 'FORMAT_FAILURE_MESSAGE: $1',
};
window.loadTimeData.getString = id => {
return window.loadTimeData.data_[id] || id;
......@@ -42,7 +48,9 @@ function setUp() {
volumeManager = new MockVolumeManager();
MockVolumeManager.installMockSingleton(volumeManager);
deviceHandler = new DeviceHandler();
progressCenter = new MockProgressCenter();
deviceHandler = new DeviceHandler(progressCenter);
}
function setUpInIncognitoContext() {
......@@ -566,34 +574,37 @@ function testDisabledDevice() {
function testFormatSucceeded() {
mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
{type: 'format_start', devicePath: '/device/path'});
assertEquals(1, Object.keys(mockChrome.notifications.items).length);
{type: 'format_start', devicePath: '/device/path', deviceLabel: 'label'});
assertEquals(1, progressCenter.getItemCount());
assertEquals(
'FORMATTING_OF_DEVICE_PENDING_MESSAGE',
mockChrome.notifications.items['formatStart:/device/path'].message);
'FORMAT_PROGRESS_MESSAGE: label',
progressCenter.getItemById('format:/device/path').message);
mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
{type: 'format_success', devicePath: '/device/path'});
assertEquals(1, Object.keys(mockChrome.notifications.items).length);
mockChrome.fileManagerPrivate.onDeviceChanged.dispatch({
type: 'format_success',
devicePath: '/device/path',
deviceLabel: 'label'
});
assertEquals(1, progressCenter.getItemCount());
assertEquals(
'FORMATTING_FINISHED_SUCCESS_MESSAGE',
mockChrome.notifications.items['formatSuccess:/device/path'].message);
'FORMAT_SUCCESS_MESSAGE: label',
progressCenter.getItemById('format:/device/path').message);
}
function testFormatFailed() {
mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
{type: 'format_start', devicePath: '/device/path'});
assertEquals(1, Object.keys(mockChrome.notifications.items).length);
{type: 'format_start', devicePath: '/device/path', deviceLabel: 'label'});
assertEquals(1, progressCenter.getItemCount());
assertEquals(
'FORMATTING_OF_DEVICE_PENDING_MESSAGE',
mockChrome.notifications.items['formatStart:/device/path'].message);
'FORMAT_PROGRESS_MESSAGE: label',
progressCenter.getItemById('format:/device/path').message);
mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
{type: 'format_fail', devicePath: '/device/path'});
assertEquals(1, Object.keys(mockChrome.notifications.items).length);
{type: 'format_fail', devicePath: '/device/path', deviceLabel: 'label'});
assertEquals(1, progressCenter.getItemCount());
assertEquals(
'FORMATTING_FINISHED_FAILURE_MESSAGE',
mockChrome.notifications.items['formatFail:/device/path'].message);
'FORMAT_FAILURE_MESSAGE: label',
progressCenter.getItemById('format:/device/path').message);
}
function testRenameSucceeded() {
......@@ -654,10 +665,9 @@ function testNotificationClicked(callback) {
function testMiscMessagesInIncognito() {
setUpInIncognitoContext();
mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
{type: 'format_start', devicePath: '/device/path'});
{type: 'format_start', devicePath: '/device/path', deviceLabel: 'label'});
// No notification sent by this instance in incognito context.
assertEquals(0, Object.keys(mockChrome.notifications.items).length);
assertFalse(mockChrome.notifications.resolver.settled);
assertEquals(0, progressCenter.getItemCount());
}
function testMountCompleteInIncognito() {
......
......@@ -48,7 +48,9 @@ const ProgressItemType = {
SYNC: 'sync',
// The item is general file transfer operation.
// This is used for the mixed operation of summarized item.
TRANSFER: 'transfer'
TRANSFER: 'transfer',
// The item is external drive format operation.
FORMAT: 'format'
};
Object.freeze(ProgressItemType);
......
......@@ -79,6 +79,7 @@
<defs>
<g id='success'><path fill='#34A853' d='M14 23.6L8.4 18l-1.9 1.9 7.5 7.4 16-16-1.9-1.8z'/></g>
<g id='failure' stroke='#EA4335' stroke-width='2.6'><circle cx='18' cy='18' r='12.1' fill='none'/><path d='M18 11v8.5m0 2.6v2.6'/></g>
<g id='hard-drive' transform='scale(1.8,1.8)' fill='#1A73E8C0'><path d="M15 2c1.1046 0 2 .8954 2 2v12c0 1.1046-.8954 2-2 2H5c-1.1046 0-2-.8954-2-2V4c0-1.1046.8954-2 2-2h10zm0 10H5v4h10v-4zm-2 1c.5523 0 1 .4477 1 1s-.4477 1-1 1-1-.4477-1-1 .4477-1 1-1zm2-9H5v6h10V4z"/></g>
</defs>
</svg>
</iron-iconset-svg>
......@@ -26,6 +26,7 @@ class PanelItem extends HTMLElement {
this.panelTypeDone = 2;
this.panelTypeError = 3;
this.panelTypeInfo = 4;
this.panelTypeFormatProgress = 5;
/** @private {number} */
this.panelType_ = this.panelTypeDefault;
......@@ -260,6 +261,10 @@ class PanelItem extends HTMLElement {
break;
case this.panelTypeInfo:
break;
case this.panelTypeFormatProgress:
this.setAttribute('indicator', 'status');
this.setAttribute('status', 'hard-drive');
break;
}
this.panelType_ = type;
......
......@@ -407,7 +407,11 @@ class ProgressCenterPanel {
setTimeout(() => {
this.feedbackHost_.attachPanelItem(panelItem);
}, this.PENDING_TIME_MS_);
panelItem.panelType = panelItem.panelTypeProgress;
if (item.type === 'format') {
panelItem.panelType = panelItem.panelTypeFormatProgress;
} else {
panelItem.panelType = panelItem.panelTypeProgress;
}
panelItem.userData = {
'source': item.sourceMessage,
'destination': item.destinationMessage,
......@@ -437,9 +441,10 @@ class ProgressCenterPanel {
panelItem.progress = item.progressRateInPercent.toString();
switch (item.state) {
case 'completed':
// Create a completed panel for copies and moves.
// Create a completed panel for copies, moves and formats.
// TODO(crbug.com/947388) decide if we want these for delete, etc.
if (item.type === 'copy' || item.type === 'move') {
if (item.type === 'copy' || item.type === 'move' ||
item.type === 'format') {
const donePanelItem = this.feedbackHost_.addPanelItem(item.id);
donePanelItem.panelType = donePanelItem.panelTypeDone;
donePanelItem.primaryText =
......
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