| Index: chrome/browser/extensions/extension_file_browser_private_api.cc
|
| diff --git a/chrome/browser/extensions/extension_file_browser_private_api.cc b/chrome/browser/extensions/extension_file_browser_private_api.cc
|
| index 964d44176bb28b5e2634610c112a7a6b7c0b438e..72614070bc142bb7cce49548dfb3c839db1d8cc1 100644
|
| --- a/chrome/browser/extensions/extension_file_browser_private_api.cc
|
| +++ b/chrome/browser/extensions/extension_file_browser_private_api.cc
|
| @@ -909,6 +909,12 @@ const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const {
|
| return Callback::Find(GetTabId());
|
| }
|
|
|
| +void FileDialogFunction::RemoveCallback() {
|
| + // Listeners expect to be invoked exactly once, so we need to remove our
|
| + // callback objects afterwards.
|
| + Callback::Remove(GetTabId());
|
| +}
|
| +
|
| // GetFileSystemRootPathOnFileThread can only be called from the file thread,
|
| // so here we are. This function takes a vector of virtual paths, converts
|
| // them to local paths and calls GetLocalPathsResponseOnUIThread with the
|
| @@ -995,6 +1001,7 @@ void SelectFileFunction::GetLocalPathsResponseOnUIThread(
|
| callback.listener()->FileSelected(files[0],
|
| index,
|
| callback.params());
|
| + RemoveCallback(); // Listeners expect to be invoked exactly once.
|
| }
|
| SendResponse(true);
|
| }
|
| @@ -1089,6 +1096,7 @@ void SelectFilesFunction::GetLocalPathsResponseOnUIThread(
|
| DCHECK(!callback.IsNull());
|
| if (!callback.IsNull()) {
|
| callback.listener()->MultiFilesSelected(files, callback.params());
|
| + RemoveCallback(); // Listeners expect to be invoked exactly once.
|
| }
|
| SendResponse(true);
|
| }
|
| @@ -1098,6 +1106,7 @@ bool CancelFileDialogFunction::RunImpl() {
|
| DCHECK(!callback.IsNull());
|
| if (!callback.IsNull()) {
|
| callback.listener()->FileSelectionCanceled(callback.params());
|
| + RemoveCallback(); // Listeners expect to be invoked exactly once.
|
| }
|
| SendResponse(true);
|
| return true;
|
|
|