Skip to content

Commit

Permalink
Show a toast when ARC cannot access the removable volume
Browse files Browse the repository at this point in the history
When the user clicks a removable storage volume on the left pane,
this CL shows a toast when the user has to change the ARC
preference for ARC apps to access the storage.

UI mock: go/filesapp-arc-extdriveaccess

BUG=936814
TEST=browser_tests --enable-pixel-output-in-tests --use-gpu-in-tests \
  --gtest_filter='*fileDisplayUsb*'
TEST=ninja -j1500 -C out/Release ui/file_manager:closure_compile

Change-Id: Id86de321c076493ed65fd2131e4a092c3f3dcc92
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1610507
Commit-Queue: Yusuke Sato <yusukes@chromium.org>
Reviewed-by: Luciano Pacheco <lucmult@chromium.org>
Cr-Commit-Position: refs/heads/master@{#660542}
  • Loading branch information
yusukes authored and Commit Bot committed May 16, 2019
1 parent 64564f7 commit d1ac7aa
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,19 @@ FileManagerPrivateSetPreferencesFunction::Run() {
Profile* profile = Profile::FromBrowserContext(browser_context());
PrefService* const service = profile->GetPrefs();

if (params->change_info.cellular_disabled)
if (params->change_info.cellular_disabled) {
service->SetBoolean(drive::prefs::kDisableDriveOverCellular,
*params->change_info.cellular_disabled);
}
if (params->change_info.arc_enabled) {
service->SetBoolean(arc::prefs::kArcEnabled,
*params->change_info.arc_enabled);
}
if (params->change_info.arc_removable_media_access_enabled) {
service->SetBoolean(
arc::prefs::kArcHasAccessToRemovableMedia,
*params->change_info.arc_removable_media_access_enabled);
}

return RespondNow(NoArguments());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ WRAPPED_INSTANTIATE_TEST_SUITE_P(
TestCase("fileDisplayMtp"),
TestCase("fileDisplayUsb"),
TestCase("fileDisplayUsbPartition"),
TestCase("fileDisplayUsbToast"),
TestCase("fileDisplayUsbNoToast"),
TestCase("fileDisplayPartitionFileTable"),
TestCase("fileSearch"),
TestCase("fileSearch").EnableMyFilesVolume(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,10 @@ std::unique_ptr<base::DictionaryValue> GetFileManagerStrings() {
SET_STRING("TOTAL_FILE_COUNT", IDS_FILE_BROWSER_TOTAL_FILE_COUNT_LABEL);
SET_STRING("IMAGE_RESOLUTION_COLUMN_LABEL",
IDS_FILE_BROWSER_IMAGE_RESOLUTION_COLUMN_LABEL);
SET_STRING("FILE_BROWSER_PLAY_STORE_ACCESS_LABEL",
IDS_FILE_BROWSER_PLAY_STORE_ACCESS_LABEL);
SET_STRING("FILE_BROWSER_OPEN_PLAY_STORE_SETTINGS_LABEL",
IDS_FILE_BROWSER_OPEN_PLAY_STORE_SETTINGS_LABEL);
SET_STRING("ANDROID_FILES_ROOT_LABEL",
IDS_FILE_BROWSER_ANDROID_FILES_ROOT_LABEL);
SET_STRING("SHOW_ALL_ANDROID_FOLDERS_OPTION",
Expand Down
2 changes: 2 additions & 0 deletions chrome/common/extensions/api/file_manager_private.idl
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,8 @@ dictionary Preferences {

dictionary PreferencesChange {
boolean? cellularDisabled;
boolean? arcEnabled;
boolean? arcRemovableMediaAccessEnabled;
};

dictionary SearchParams {
Expand Down
2 changes: 2 additions & 0 deletions third_party/closure_compiler/externs/file_manager_private.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ chrome.fileManagerPrivate.Preferences;
/**
* @typedef {{
* cellularDisabled: (boolean|undefined),
* arcEnabled: (boolean|undefined),
* arcRemovableMediaAccessEnabled: (boolean|undefined)
* }}
*/
chrome.fileManagerPrivate.PreferencesChange;
Expand Down
6 changes: 6 additions & 0 deletions ui/chromeos/file_manager_strings.grdp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
<message name="IDS_FILE_BROWSER_ANDROID_FILES_ROOT_LABEL" desc="A label for the 'Play files' root which shows Android files. 'Play' in this label is an abbreviation of 'Google Play', so it should not be translated. Use sentence case.">
Play files
</message>
<message name="IDS_FILE_BROWSER_PLAY_STORE_ACCESS_LABEL" desc="A label for the toast which shows when Play Store apps don't have access to external storage devices.">
Play Store applications can't access this device
</message>
<message name="IDS_FILE_BROWSER_OPEN_PLAY_STORE_SETTINGS_LABEL" desc="A button for the toast which shows when Play Store apps don't have access to external storage devices.">
Open settings
</message>
<message name="IDS_FILE_BROWSER_SHOW_ALL_ANDROID_FOLDERS_OPTION" desc="A label for an option menu item to show all Android folders. By default, only several folders are visible to users, and users will click this option menu item to show all folders. 'Play' in this label is an abbreviation of 'Google Play', so it should not be translated.">
Show all Play folders
</message>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7aec566f896003a10488b91b1dbdb0e8bf8390f0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7aec566f896003a10488b91b1dbdb0e8bf8390f0
Original file line number Diff line number Diff line change
Expand Up @@ -886,3 +886,12 @@ test.util.async.getVolumesCount = callback => {
callback(volumeManager.volumeInfoList.length);
});
};

/**
* Updates the preferences.
* @param {chrome.fileManagerPrivate.PreferencesChange} preferences Preferences
* to set.
*/
test.util.sync.setPreferences = preferences => {
chrome.fileManagerPrivate.setPreferences(preferences);
};
39 changes: 39 additions & 0 deletions ui/file_manager/file_manager/foreground/js/file_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,10 @@ FileManager.prototype = /** @struct */ {
/** @param {!Event} event */
event => {
this.navigationUma_.onDirectoryChanged(event.newDirEntry);
if (event.volumeChanged) {
this.showArcStorageToast_(
this.volumeManager_.getVolumeInfo(event.newDirEntry));
}
});

this.initCommands_();
Expand Down Expand Up @@ -1634,4 +1638,39 @@ FileManager.prototype = /** @struct */ {
this.directoryTree.redraw(false);
});
};

/**
* Shows a toast for ARC storage when needed.
* @param {VolumeInfo} volumeInfo Volume information currently selected.
*/
FileManager.prototype.showArcStorageToast_ = function(volumeInfo) {
if (!volumeInfo ||
volumeInfo.volumeType !== VolumeManagerCommon.VolumeType.REMOVABLE) {
// The toast is for removable volumes.
return;
}
const key = 'show-arc-storage-toast-shown';
if (window.sessionStorage.getItem(key)) {
// We show the toast only once.
// TODO(yusukes): We should show the UI only once *per user session*.
// Since sessionStorage is deleted when you close the app window, the
// current code is not perfect.
return;
}
chrome.fileManagerPrivate.getPreferences(pref => {
if (!pref.arcEnabled || pref.arcRemovableMediaAccessEnabled) {
// We don't show the toast when ARC is disabled or the setting has
// already been enabled.
return;
}
this.ui.toast.show(str('FILE_BROWSER_PLAY_STORE_ACCESS_LABEL'), {
text: str('FILE_BROWSER_OPEN_PLAY_STORE_SETTINGS_LABEL'),
callback: () => {
chrome.fileManagerPrivate.openSettingsSubpage(
'storage/externalStoragePreferences');
}
});
window.sessionStorage.setItem(key, 'true');
});
};
})();
117 changes: 117 additions & 0 deletions ui/file_manager/integration_tests/file_manager/file_display.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,32 @@ async function fileDisplay(path, defaultEntries) {
await remoteCall.waitForFiles(appId, expectedList);
}

/**
* Waits 250ms and fail if toast shows in this time.
*
* @param {string} appId The app's window id.
*/
async function checkHiddenToast(appId) {
const start = new Date();
const caller = getCaller();
await repeatUntil(async () => {
if (new Date() - start > 250 /* ms */) {
// Waited long enough. End with success.
return;
}

const visibleQuery = ['#toast', '#container:not([hidden])'];
const visibleToast = await remoteCall.callRemoteTestUtil(
'deepQueryAllElements', appId, [visibleQuery]);

// Fails if finds a non-hidden toast.
chrome.test.assertTrue(
visibleToast.length == 0, 'Toast is visible when it shouldn\'t');

return pending(caller, 'Waiting to see if toast will show.');
});
}

/**
* Tests files display in Downloads.
*/
Expand Down Expand Up @@ -232,6 +258,97 @@ testcase.fileDisplayUsbPartition = async () => {
chrome.test.assertTrue('removable' !== childVolumeType);
};

/**
* Tests USB toast display for ARC on clicking a USB volume.
*/
testcase.fileDisplayUsbToast = async () => {
const USB_VOLUME_QUERY = '#directory-tree [volume-type-icon="removable"]';

// Open Files app on local downloads.
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);

// Mount USB volume in the Downloads window.
await sendTestMessage({name: 'mountFakeUsb'});

// Wait for the USB mount.
await remoteCall.waitForElement(appId, USB_VOLUME_QUERY);

// Enable ARC, but disallow ARC from accessing the USB volume so that the
// toast UI will be shown.
const preferences = {
arcEnabled: true,
arcRemovableMediaAccessEnabled: false,
};
await remoteCall.callRemoteTestUtil('setPreferences', null, [preferences]);

// Click to open the USB volume.
await remoteCall.waitAndClickElement(appId, USB_VOLUME_QUERY);

// Verify the toast UI.
await remoteCall.waitForElement(
appId, ['#toast', '#container:not([hidden])']);

// Wait for the toast to disappear.
await remoteCall.waitForElement(appId, ['#toast', '#container[hidden]']);

// Navigate to My files.
await remoteCall.waitAndClickElement(appId, '[root-type-icon=\'my_files\']');

// Verify the toast UI never shows up.
await checkHiddenToast(appId);

// Navigate to the USB volume again.
await remoteCall.waitAndClickElement(appId, USB_VOLUME_QUERY);

// Verify the toast UI never shows up again.
await checkHiddenToast(appId);
};

/**
* Tests USB toast won't show up when ARC is disabled or the access has already
* been granted.
*/
testcase.fileDisplayUsbNoToast = async () => {
const USB_VOLUME_QUERY = '#directory-tree [volume-type-icon="removable"]';

// Open Files app on local downloads.
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);

// Mount USB volume in the Downloads window.
await sendTestMessage({name: 'mountFakeUsb'});

// Wait for the USB mount.
await remoteCall.waitForElement(appId, USB_VOLUME_QUERY);

// Disable ARC so that the toast UI won't be shown.
const preferences = {
arcEnabled: false,
};
await remoteCall.callRemoteTestUtil('setPreferences', null, [preferences]);

// Click to open the USB volume.
await remoteCall.waitAndClickElement(appId, USB_VOLUME_QUERY);

// Verify the toast UI never shows up.
await checkHiddenToast(appId);

// Navigate to My files.
await remoteCall.waitAndClickElement(appId, '[root-type-icon=\'my_files\']');

// Enable ARC and its storage access so that the toast UI won't be shown.
const preferences2 = {
arcEnabled: true,
arcRemovableMediaAccessEnabled: true,
};
await remoteCall.callRemoteTestUtil('setPreferences', null, [preferences2]);

// Navigate to the USB volume again.
await remoteCall.waitAndClickElement(appId, USB_VOLUME_QUERY);

// Verify the toast UI is still not shown.
await checkHiddenToast(appId);
};

/**
* Tests partitions display in the file table when root removable entry
* is selected. Checks file system type is displayed.
Expand Down

0 comments on commit d1ac7aa

Please sign in to comment.