| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_MEDIA_GALLERIES_WIN_MTP_DEVICE_DELEGATE_IMPL_WIN_H_ |
| #define CHROME_BROWSER_MEDIA_GALLERIES_WIN_MTP_DEVICE_DELEGATE_IMPL_WIN_H_ |
| |
| #include <queue> |
| |
| #include "base/callback.h" |
| #include "base/location.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/platform_file.h" |
| #include "base/strings/string16.h" |
| #include "base/win/scoped_comptr.h" |
| #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h" |
| #include "webkit/browser/fileapi/async_file_util.h" |
| |
| namespace base { |
| class FilePath; |
| class SequencedTaskRunner; |
| } |
| |
| class SnapshotFileDetails; |
| struct SnapshotRequestInfo; |
| |
| // MTPDeviceDelegateImplWin is used to communicate with the media transfer |
| // protocol (MTP) device to complete file system operations. These operations |
| // are performed asynchronously on a blocking pool thread since the device |
| // access may be slow and may take a long time to complete. MTP |
| // device can have multiple data storage partitions. MTPDeviceDelegateImplWin |
| // is instantiated per MTP device storage partition using |
| // CreateMTPDeviceAsyncDelegate(). MTPDeviceDelegateImplWin lives on the IO |
| // thread. |
| class MTPDeviceDelegateImplWin : public MTPDeviceAsyncDelegate { |
| public: |
| // Structure used to represent MTP device storage partition details. |
| struct StorageDeviceInfo { |
| StorageDeviceInfo(const base::string16& pnp_device_id, |
| const base::string16& registered_device_path, |
| const base::string16& storage_object_id); |
| |
| // The PnP Device Id, used to open the device for communication, |
| // e.g. "\\?\usb#vid_04a9&pid_3073#12#{6ac27878-a6fa-4155-ba85-f1d4f33}". |
| const base::string16 pnp_device_id; |
| |
| // The media file system root path, which is obtained during the |
| // registration of MTP device storage partition as a file system, |
| // e.g. "\\MTP:StorageSerial:SID-{10001,E,9823}:237483". |
| const base::string16 registered_device_path; |
| |
| // The MTP device storage partition object identifier, used to enumerate the |
| // storage contents, e.g. "s10001". |
| const base::string16 storage_object_id; |
| }; |
| |
| private: |
| friend void OnGetStorageInfoCreateDelegate( |
| const base::string16& device_location, |
| const CreateMTPDeviceAsyncDelegateCallback& callback, |
| base::string16* pnp_device_id, |
| base::string16* storage_object_id, |
| bool succeeded); |
| |
| enum InitializationState { |
| UNINITIALIZED = 0, |
| PENDING_INIT, |
| INITIALIZED |
| }; |
| |
| // Used to represent pending task details. |
| struct PendingTaskInfo { |
| PendingTaskInfo(const tracked_objects::Location& location, |
| const base::Callback<base::PlatformFileError(void)>& task, |
| const base::Callback<void(base::PlatformFileError)>& reply); |
| |
| const tracked_objects::Location location; |
| const base::Callback<base::PlatformFileError(void)> task; |
| const base::Callback<void(base::PlatformFileError)> reply; |
| }; |
| |
| // Defers the device initializations until the first file operation request. |
| // Do all the initializations in EnsureInitAndRunTask() function. |
| MTPDeviceDelegateImplWin(const base::string16& registered_device_path, |
| const base::string16& pnp_device_id, |
| const base::string16& storage_object_id); |
| |
| // Destructed via CancelPendingTasksAndDeleteDelegate(). |
| virtual ~MTPDeviceDelegateImplWin(); |
| |
| // MTPDeviceAsyncDelegate: |
| virtual void GetFileInfo( |
| const base::FilePath& file_path, |
| const GetFileInfoSuccessCallback& success_callback, |
| const ErrorCallback& error_callback) OVERRIDE; |
| virtual void ReadDirectory( |
| const base::FilePath& root, |
| const ReadDirectorySuccessCallback& success_callback, |
| const ErrorCallback& error_callback) OVERRIDE; |
| virtual void CreateSnapshotFile( |
| const base::FilePath& device_file_path, |
| const base::FilePath& local_path, |
| const CreateSnapshotFileSuccessCallback& success_callback, |
| const ErrorCallback& error_callback) OVERRIDE; |
| virtual void CancelPendingTasksAndDeleteDelegate() OVERRIDE; |
| |
| // Ensures the device is initialized for communication by doing a |
| // call-and-reply to a blocking pool thread. |task_info.task| runs on a |
| // blocking pool thread and |task_info.reply| runs on the IO thread. |
| // |
| // If the device is already initialized, post the |task_info.task| |
| // immediately on a blocking pool thread. |
| // |
| // If the device is uninitialized, store the |task_info| in a pending task |
| // list and then runs all the pending tasks once the device is successfully |
| // initialized. |
| void EnsureInitAndRunTask(const PendingTaskInfo& task_info); |
| |
| // Writes data chunk from the device to the snapshot file path based on the |
| // parameters in |current_snapshot_details_| by doing a call-and-reply to a |
| // blocking pool thread. |
| void WriteDataChunkIntoSnapshotFile(); |
| |
| // Processes the next pending request. |
| void ProcessNextPendingRequest(); |
| |
| // Handles the event that the device is initialized. |succeeded| indicates |
| // whether device initialization succeeded or not. If the device is |
| // successfully initialized, runs the next pending task. |
| void OnInitCompleted(bool succeeded); |
| |
| // Called when GetFileInfo() completes. |file_info| specifies the requested |
| // file details. |error| specifies the platform file error code. |
| // |
| // If the GetFileInfo() succeeds, |success_callback| is invoked to notify the |
| // caller about the |file_info| details. |
| // |
| // If the GetFileInfo() fails, |file_info| is not set and |error_callback| is |
| // invoked to notify the caller about the platform file |error|. |
| void OnGetFileInfo(const GetFileInfoSuccessCallback& success_callback, |
| const ErrorCallback& error_callback, |
| base::PlatformFileInfo* file_info, |
| base::PlatformFileError error); |
| |
| // Called when ReadDirectory() completes. |file_list| contains the directory |
| // file entries information. |error| specifies the platform file error code. |
| // |
| // If the ReadDirectory() succeeds, |success_callback| is invoked to notify |
| // the caller about the directory file entries. |
| // |
| // If the ReadDirectory() fails, |file_list| is not set and |error_callback| |
| // is invoked to notify the caller about the platform file |error|. |
| void OnDidReadDirectory(const ReadDirectorySuccessCallback& success_callback, |
| const ErrorCallback& error_callback, |
| fileapi::AsyncFileUtil::EntryList* file_list, |
| base::PlatformFileError error); |
| |
| // Called when the get file stream request completes. |
| // |file_details.request_info| contains the CreateSnapshot request param |
| // details. |error| specifies the platform file error code. |
| // |
| // If the file stream of the device file is successfully |
| // fetched, |file_details| will contain the required details for the creation |
| // of the snapshot file. |
| // |
| // If the get file stream request fails, |error| is set accordingly. |
| void OnGetFileStream(scoped_ptr<SnapshotFileDetails> file_details, |
| base::PlatformFileError error); |
| |
| // Called when WriteDataChunkIntoSnapshotFile() completes. |
| // |bytes_written| specifies the number of bytes written into the |
| // |snapshot_file_path| during the last write operation. |
| // |
| // If the write operation succeeds, |bytes_written| is set to a non-zero |
| // value. |
| // |
| // If the write operation fails, |bytes_written| is set to zero. |
| void OnWroteDataChunkIntoSnapshotFile( |
| const base::FilePath& snapshot_file_path, |
| DWORD bytes_written); |
| |
| // Portable device initialization state. |
| InitializationState init_state_; |
| |
| // The task runner where the device operation tasks runs. |
| scoped_refptr<base::SequencedTaskRunner> media_task_runner_; |
| |
| // Device storage partition details |
| // (e.g. device path, PnP device id and storage object id). |
| StorageDeviceInfo storage_device_info_; |
| |
| // Used to track the current state of the snapshot file (e.g how many bytes |
| // written to the snapshot file, optimal data transfer size, source file |
| // stream, etc). |
| // |
| // A snapshot file is created incrementally. CreateSnapshotFile request reads |
| // and writes the snapshot file data in chunks. In order to retain the order |
| // of the snapshot file requests, make sure there is only one active snapshot |
| // file request at any time. |
| scoped_ptr<SnapshotFileDetails> current_snapshot_details_; |
| |
| // A list of pending tasks that needs to be run when the device is |
| // initialized or when the current task in progress is complete. |
| std::queue<PendingTaskInfo> pending_tasks_; |
| |
| // Used to make sure only one task is in progress at any time. |
| bool task_in_progress_; |
| |
| // For callbacks that may run after destruction. |
| base::WeakPtrFactory<MTPDeviceDelegateImplWin> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MTPDeviceDelegateImplWin); |
| }; |
| |
| #endif // CHROME_BROWSER_MEDIA_GALLERIES_WIN_MTP_DEVICE_DELEGATE_IMPL_WIN_H_ |