Commit 36a75677 authored by Zain Afzal's avatar Zain Afzal Committed by Commit Bot

Make request save file return a pickedFile.

Previously the media app was unable to perform a save as operation on a
file obtained from a drag and drop or from a paste event. This was
because the logic surrounding the operation was encapsulated in
ReceivedFile which is a class the media app does not have access to.
This cl updates the requestSaveFile IPC to return a ReceivedFile
instead of returning a file token, allowing the media app to obtain a
native file, overwrite it and copy over it's functions so future saves
can happen in place.

The google3 side of this change is @ cl/334717684.

Bug: b/165769056, b/169630668
Change-Id: Ied8dd540f9f319b18b427e6566851bc628ed3204
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2439969Reviewed-by: default avatarTrent Apted <tapted@chromium.org>
Reviewed-by: default avatardstockwell <dstockwell@google.com>
Commit-Queue: Zain Afzal <zafzal@google.com>
Cr-Commit-Position: refs/heads/master@{#812607}
parent 1b05ee04
...@@ -245,7 +245,16 @@ guestMessagePipe.registerHandler(Message.REQUEST_SAVE_FILE, async (message) => { ...@@ -245,7 +245,16 @@ guestMessagePipe.registerHandler(Message.REQUEST_SAVE_FILE, async (message) => {
/** @type {!RequestSaveFileMessage} */ (message); /** @type {!RequestSaveFileMessage} */ (message);
const handle = await pickWritableFile(suggestedName, mimeType); const handle = await pickWritableFile(suggestedName, mimeType);
/** @type {!RequestSaveFileResponse} */ /** @type {!RequestSaveFileResponse} */
const response = {token: generateToken(handle)}; const response = {
pickedFileContext: {
token: generateToken(handle),
file: assertCast(await handle.getFile()),
name: handle.name,
error: '',
canDelete: false,
canRename: false,
}
};
return response; return response;
}); });
......
...@@ -145,17 +145,17 @@ mediaApp.ClientApiDelegate = function() {}; ...@@ -145,17 +145,17 @@ mediaApp.ClientApiDelegate = function() {};
mediaApp.ClientApiDelegate.prototype.openFeedbackDialog = function() {}; mediaApp.ClientApiDelegate.prototype.openFeedbackDialog = function() {};
/** /**
* Request for the user to be prompted with a save file dialog. Once the user * Request for the user to be prompted with a save file dialog. Once the user
* selects a location a new file handle is created and a unique token to that * selects a location a new file handle is created and a new AbstractFile
* file will be returned. This token can be then used with saveCopy(). The file * representing that file will be returned. This can be then used in a save as
* extension on `suggestedName` and the provided `mimeType` are used to inform * operation. The file extension on `suggestedName` and the provided `mimeType`
* the save as dialog what file should be created. Once the Native Filesystem * are used to inform the save as dialog what file should be created. Once the
* API allows, this save as dialog will additionally have the filename input be * Native Filesystem API allows, this save as dialog will additionally have the
* pre-filled with `suggestedName`. * filename input be pre-filled with `suggestedName`.
* TODO(b/161087799): Update function description once Native Filesystem API * TODO(b/161087799): Update function description once Native Filesystem API
* supports suggestedName. * supports suggestedName.
* @param {string} suggestedName * @param {string} suggestedName
* @param {string} mimeType * @param {string} mimeType
* @return {!Promise<number>} * @return {!Promise<!mediaApp.AbstractFile>}
*/ */
mediaApp.ClientApiDelegate.prototype.requestSaveFile = function( mediaApp.ClientApiDelegate.prototype.requestSaveFile = function(
suggestedName, mimeType) {}; suggestedName, mimeType) {};
......
...@@ -140,7 +140,7 @@ let RequestSaveFileMessage; ...@@ -140,7 +140,7 @@ let RequestSaveFileMessage;
* Response message sent by the privileged context with a unique identifier for * Response message sent by the privileged context with a unique identifier for
* the new writable file created on disk by the corresponding request save * the new writable file created on disk by the corresponding request save
* file message. * file message.
* @typedef {{token: number}} * @typedef {{pickedFileContext: !FileContext}}
*/ */
let RequestSaveFileResponse; let RequestSaveFileResponse;
......
...@@ -223,7 +223,7 @@ const DELEGATE = { ...@@ -223,7 +223,7 @@ const DELEGATE = {
/** /**
* @param {string} suggestedName * @param {string} suggestedName
* @param {string} mimeType * @param {string} mimeType
* @return {!Promise<number>} * @return {!Promise<!mediaApp.AbstractFile>}
*/ */
async requestSaveFile(suggestedName, mimeType) { async requestSaveFile(suggestedName, mimeType) {
/** @type {!RequestSaveFileMessage} */ /** @type {!RequestSaveFileMessage} */
...@@ -232,7 +232,7 @@ const DELEGATE = { ...@@ -232,7 +232,7 @@ const DELEGATE = {
/** @type {!RequestSaveFileResponse} */ ( /** @type {!RequestSaveFileResponse} */ (
await parentMessagePipe.sendMessage( await parentMessagePipe.sendMessage(
Message.REQUEST_SAVE_FILE, msg)); Message.REQUEST_SAVE_FILE, msg));
return response.token; return new ReceivedFile(response.pickedFileContext);
}, },
/** /**
* @return {!Promise<undefined>} * @return {!Promise<undefined>}
......
...@@ -98,9 +98,9 @@ async function runTestQuery(data) { ...@@ -98,9 +98,9 @@ async function runTestQuery(data) {
if (!existingFile) { if (!existingFile) {
result = 'requestSaveFile failed, no file loaded'; result = 'requestSaveFile failed, no file loaded';
} else { } else {
const token = await DELEGATE.requestSaveFile( const pickedFile = await DELEGATE.requestSaveFile(
existingFile.name, existingFile.mimeType); existingFile.name, existingFile.mimeType);
result = token.toString(); result = assertCast(pickedFile.token).toString();
} }
} else if (data.saveAs) { } else if (data.saveAs) {
const existingFile = assertCast(lastReceivedFileList).item(0); const existingFile = assertCast(lastReceivedFileList).item(0);
...@@ -109,10 +109,11 @@ async function runTestQuery(data) { ...@@ -109,10 +109,11 @@ async function runTestQuery(data) {
} else { } else {
const file = firstReceivedItem(); const file = firstReceivedItem();
try { try {
const token = await DELEGATE.requestSaveFile( const token = (await DELEGATE.requestSaveFile(
existingFile.name, existingFile.mimeType); existingFile.name, existingFile.mimeType))
.token;
const testBlob = new Blob([data.saveAs]); const testBlob = new Blob([data.saveAs]);
await assertCast(file.saveAs).call(file, testBlob, token); await assertCast(file.saveAs).call(file, testBlob, assertCast(token));
result = file.name; result = file.name;
extraResultData = {blobText: await file.blob.text()}; extraResultData = {blobText: await file.blob.text()};
} catch (/** @type{!Error} */ error) { } catch (/** @type{!Error} */ error) {
......
...@@ -922,6 +922,8 @@ TEST_F('MediaAppUIBrowserTest', 'RequestSaveFileIPC', async () => { ...@@ -922,6 +922,8 @@ TEST_F('MediaAppUIBrowserTest', 'RequestSaveFileIPC', async () => {
const result = await sendTestMessage({requestSaveFile: true}); const result = await sendTestMessage({requestSaveFile: true});
const options = await chooseEntries; const options = await chooseEntries;
const lastToken = [...tokenMap.keys()].slice(-1)[0]; const lastToken = [...tokenMap.keys()].slice(-1)[0];
// Check the token matches to confirm the ReceivedFile returned represents the
// new file created on disk.
assertMatch(result.testQueryResult, lastToken); assertMatch(result.testQueryResult, lastToken);
assertEquals(options.types.length, 1); assertEquals(options.types.length, 1);
assertEquals(options.types[0].description, '.png'); assertEquals(options.types[0].description, '.png');
......
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