blob: aa142bcf7de1ab627d3aea760144665d6d19a0b8 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_ASH_CLOUD_UPLOAD_CLOUD_UPLOAD_DIALOG_H_
#define CHROME_BROWSER_UI_WEBUI_ASH_CLOUD_UPLOAD_CLOUD_UPLOAD_DIALOG_H_
#include <vector>
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ash/file_manager/file_tasks.h"
#include "chrome/browser/ash/file_system_provider/mount_path_util.h"
#include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom.h"
#include "chrome/browser/ui/webui/ash/system_web_dialog_delegate.h"
#include "storage/browser/file_system/file_system_url.h"
#include "ui/gfx/geometry/size.h"
class Profile;
namespace extensions::app_file_handler_util {
class MimeTypeCollector;
} // namespace extensions::app_file_handler_util
namespace file_manager::file_tasks {
FORWARD_DECLARE_TEST(DriveTest, OpenFileInDrive);
FORWARD_DECLARE_TEST(OneDriveTest, OpenFileFromODFS);
FORWARD_DECLARE_TEST(OneDriveTest, OpenFileNotFromODFS);
FORWARD_DECLARE_TEST(OneDriveTest, OpenFileFromAndroidOneDriveViaODFS);
FORWARD_DECLARE_TEST(OneDriveTest,
FailToOpenFileFromAndroidOneDriveViaODFSDiffEmail);
FORWARD_DECLARE_TEST(OneDriveTest, FailToOpenFileFromAndroidOneDriveNotOnODFS);
FORWARD_DECLARE_TEST(
OneDriveTest,
FailToOpenFileFromAndroidOneDriveDirectoryNotAccessibleToODFS);
} // namespace file_manager::file_tasks
namespace ash::cloud_upload {
struct ODFSFileSystemAndPath {
file_system_provider::ProvidedFileSystemInterface* file_system;
base::FilePath file_path_within_odfs;
};
// The string conversions of ash::cloud_upload::mojom::UserAction.
const char kUserActionCancel[] = "cancel";
const char kUserActionSetUpOneDrive[] = "setup-onedrive";
const char kUserActionUploadToGoogleDrive[] = "upload-drive";
const char kUserActionUploadToOneDrive[] = "upload-onedrive";
const char kUserActionConfirmOrUploadToGoogleDrive[] =
"confirm-or-upload-google-drive";
const char kUserActionConfirmOrUploadToOneDrive[] =
"confirm-or-upload-onedrive";
// Custom action ids passed from ODFS.
const char kOneDriveUrlActionId[] = "HIDDEN_ONEDRIVE_URL";
const char kUserEmailActionId[] = "HIDDEN_ONEDRIVE_USER_EMAIL";
// Either OneDrive for the Office PWA or Drive for Drive Web editing.
enum class CloudProvider {
kGoogleDrive,
kOneDrive,
};
class CloudUploadDialog;
// The business logic for running setup, moving files to a cloud provider, and
// opening files on cloud providers. Spawns instances of `CloudUploadDialog` if
// necessary to run setup or get confirmation from the user.
class CloudOpenTask : public BrowserListObserver,
public base::RefCounted<CloudOpenTask> {
public:
CloudOpenTask(const CloudOpenTask&) = delete;
CloudOpenTask& operator=(const CloudOpenTask&) = delete;
// This is the main public entry-point to the functionality in this file.
// Opens the `file_urls` from the `cloud_provider`. Runs setup for Office
// files if it has not been run before. Uploads the files to the cloud if
// needed. Returns false if `file_urls` was empty or the setup/upload process
// failed before any async step started. `CloudOpenTask` is refcounted and
// lives until the task is complete or has failed, via bound `this` pointers
// in the closures used for async steps.
static bool Execute(Profile* profile,
const std::vector<storage::FileSystemURL>& file_urls,
const CloudProvider cloud_provider,
gfx::NativeWindow modal_parent);
// Set the local tasks that are passed to the File Handler dialog. Normally
// tasks are calculated internally by this class before displaying this
// dialog. Some tests don't display the dialog, but only test post-dialog
// logic.
void SetTasksForTest(
const std::vector<::file_manager::file_tasks::TaskDescriptor>& tasks);
// BrowserListObserver implementation.
// This is called when we are waiting for a new Files app window to be
// launched, to be used as the modal parent. This is triggered by
// ShowDialog().
void OnBrowserAdded(Browser* browser) override;
FRIEND_TEST_ALL_PREFIXES(FileHandlerDialogBrowserTest,
OnDialogCompleteOpensFileTasks);
FRIEND_TEST_ALL_PREFIXES(FileHandlerDialogBrowserTest,
OnDialogCompleteNoCrash);
FRIEND_TEST_ALL_PREFIXES(FixUpFlowBrowserTest,
OneDriveSetUpChangesDefaultTaskWhenSetUpIncomplete);
FRIEND_TEST_ALL_PREFIXES(
FixUpFlowBrowserTest,
OneDriveSetUpDoesNotChangeDefaultTaskWhenSetUpComplete);
FRIEND_TEST_ALL_PREFIXES(::file_manager::file_tasks::DriveTest,
OpenFileInDrive);
FRIEND_TEST_ALL_PREFIXES(::file_manager::file_tasks::OneDriveTest,
OpenFileFromODFS);
FRIEND_TEST_ALL_PREFIXES(::file_manager::file_tasks::OneDriveTest,
OpenFileNotFromODFS);
FRIEND_TEST_ALL_PREFIXES(::file_manager::file_tasks::OneDriveTest,
OpenFileFromAndroidOneDriveViaODFS);
FRIEND_TEST_ALL_PREFIXES(::file_manager::file_tasks::OneDriveTest,
FailToOpenFileFromAndroidOneDriveViaODFSDiffEmail);
FRIEND_TEST_ALL_PREFIXES(::file_manager::file_tasks::OneDriveTest,
FailToOpenFileFromAndroidOneDriveNotOnODFS);
FRIEND_TEST_ALL_PREFIXES(
::file_manager::file_tasks::OneDriveTest,
FailToOpenFileFromAndroidOneDriveDirectoryNotAccessibleToODFS);
private:
friend class RefCounted<CloudOpenTask>; // Allow destruction by RefCounted<>.
friend class CloudOpenTaskBrowserTest;
CloudOpenTask(Profile* profile,
std::vector<storage::FileSystemURL> file_urls,
const CloudProvider cloud_provider,
gfx::NativeWindow modal_parent);
~CloudOpenTask() override;
// See the .cc implementation for comments on private methods.
bool ExecuteInternal();
void OpenOrMoveFiles();
void OpenAlreadyHostedDriveUrls();
void OpenODFSUrls();
void OpenAndroidOneDriveUrlsIfAccountMatchedODFS();
void CheckEmailAndOpenURLs(const std::string& android_onedrive_email,
const file_system_provider::Actions& actions,
base::File::Error result);
bool ShouldShowConfirmationDialog();
void ConfirmMoveOrStartUpload();
void StartUpload();
void FinishedDriveUpload(const GURL& url);
void FinishedOneDriveUpload(base::WeakPtr<Profile> profile_weak_ptr,
const storage::FileSystemURL& url);
bool InitAndShowDialog(mojom::DialogPage dialog_page);
mojom::DialogArgsPtr CreateDialogArgs(mojom::DialogPage dialog_page);
void ShowDialog(mojom::DialogArgsPtr args,
const mojom::DialogPage dialog_page,
std::unique_ptr<::file_manager::file_tasks::ResultingTasks>
resulting_tasks);
void SetTaskArgs(mojom::DialogArgsPtr& args,
std::unique_ptr<::file_manager::file_tasks::ResultingTasks>
resulting_tasks);
void OnDialogComplete(const std::string& user_response);
void LaunchLocalFileTask(const std::string& string_task_position);
void LocalTaskExecuted(
const ::file_manager::file_tasks::TaskDescriptor& task,
extensions::api::file_manager_private::TaskResult result,
std::string error_message);
void FindTasksForDialog(::file_manager::file_tasks::FindTasksCallback
find_all_types_of_tasks_callback);
void ConstructEntriesAndFindTasks(
const std::vector<base::FilePath>& file_paths,
const std::vector<GURL>& gurls,
std::unique_ptr<extensions::app_file_handler_util::MimeTypeCollector>
mime_collector,
::file_manager::file_tasks::FindTasksCallback
find_all_types_of_tasks_callback,
std::unique_ptr<std::vector<std::string>> mime_types);
raw_ptr<Profile, ExperimentalAsh> profile_;
std::vector<storage::FileSystemURL> file_urls_;
CloudProvider cloud_provider_;
gfx::NativeWindow modal_parent_;
std::vector<::file_manager::file_tasks::TaskDescriptor> local_tasks_;
size_t pending_uploads_ = 0;
CloudUploadDialog* pending_dialog_ = nullptr;
};
// Return True if feature `kUploadOfficeToCloud` is enabled and is eligible for
// the user of the |profile|. A user is eligible if they are not managed.
bool IsEligibleAndEnabledUploadOfficeToCloud(Profile* profile);
// Returns True if OneDrive is the selected `cloud_provider` but either ODFS
// is not mounted or the Office PWA is not installed. Returns False otherwise.
bool ShouldFixUpOffice(Profile* profile, const CloudProvider cloud_provider);
// Returns True if the url is on ODFS.
bool UrlIsOnODFS(Profile* profile, const FileSystemURL& url);
// Returns True if the url is on the Android OneDrive DocumentsProvider.
bool UrlIsOnAndroidOneDrive(Profile* profile, const FileSystemURL& url);
// Return the email from the Root Document Id of the Android OneDrive
// DocumentsProvider.
absl::optional<std::string> GetEmailFromAndroidOneDriveRootDoc(
const std::string& root_document_id);
// If the Microsoft account logged into the Android OneDrive matches the account
// logged into ODFS, open office files from ODFS that were originally selected
// from Android OneDrive. Open the files in the MS 365 PWA. Fails if the Android
// OneDrive URLS cannot be converted to valid ODFS file paths.
void OpenAndroidOneDriveUrlsIfAccountMatchedODFS(
Profile* profile,
const std::vector<storage::FileSystemURL>& android_onedrive_urls);
// Converts the |android_onedrive_file_url| for a file in OneDrive to the
// equivalent ODFS file path which is then parsed to detect the corresponding
// ODFS ProvidedFileSystemInterface and relative file path. There may or may not
// exist a file for the returned relative file path. The conversion can be done
// for files in OneDrive that can be accessed via Android OneDrive or ODFS.
// These are the users' own files - in the Android OneDrive "Files" directory.
// Fails if an equivalent ODFS file path can't be constructed.
absl::optional<ODFSFileSystemAndPath> AndroidOneDriveUrlToODFS(
Profile* profile,
const FileSystemURL& android_onedrive_file_url);
// Defines the web dialog used to help users upload Office files to the cloud.
class CloudUploadDialog : public SystemWebDialogDelegate {
public:
using UploadRequestCallback =
base::OnceCallback<void(const std::string& user_response)>;
CloudUploadDialog(const CloudUploadDialog&) = delete;
CloudUploadDialog& operator=(const CloudUploadDialog&) = delete;
CloudUploadDialog(mojom::DialogArgsPtr args,
UploadRequestCallback callback,
const mojom::DialogPage dialog_page,
bool office_move_confirmation_shown);
static bool IsODFSMounted(Profile* profile);
static bool IsOfficeWebAppInstalled(Profile* profile);
void OnDialogShown(content::WebUI* webui) override;
void OnDialogClosed(const std::string& json_retval) override;
protected:
~CloudUploadDialog() override;
ui::ModalType GetDialogModalType() const override;
bool ShouldCloseDialogOnEscape() const override;
bool ShouldShowCloseButton() const override;
void GetDialogSize(gfx::Size* size) const override;
private:
FRIEND_TEST_ALL_PREFIXES(FixUpFlowBrowserTest,
OneDriveSetUpChangesDefaultTaskWhenSetUpIncomplete);
FRIEND_TEST_ALL_PREFIXES(
FixUpFlowBrowserTest,
OneDriveSetUpDoesNotChangeDefaultTaskWhenSetUpComplete);
mojom::DialogArgsPtr dialog_args_;
UploadRequestCallback callback_;
mojom::DialogPage dialog_page_;
size_t num_local_tasks_;
bool office_move_confirmation_shown_;
};
} // namespace ash::cloud_upload
#endif // CHROME_BROWSER_UI_WEBUI_ASH_CLOUD_UPLOAD_CLOUD_UPLOAD_DIALOG_H_