1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// File contains the fileBrowserHandlerInternal.selectFile extension function.
6// The function prompts user to select a file path to be used by the caller. It
7// will fail if it isn't invoked by a user gesture (e.g. a mouse click or a
8// keyboard key press).
9// Note that the target file is never actually created by this function, even
10// if the selected path doesn't exist.
11
12#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_FILE_BROWSER_HANDLER_API_H_
13#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_FILE_BROWSER_HANDLER_API_H_
14
15#include <string>
16#include <vector>
17
18#include "base/files/file_path.h"
19#include "chrome/browser/extensions/extension_function.h"
20
21class Browser;
22class FileBrowserHandlerInternalSelectFileFunction;
23
24namespace file_manager {
25
26// Interface that is used by FileBrowserHandlerInternalSelectFileFunction to
27// select the file path that should be reported back to the extension function
28// caller.  Nobody will take the ownership of the interface implementation, so
29// it should delete itself once it's done.
30class FileSelector {
31 public:
32  virtual ~FileSelector() {}
33
34  // Starts the file selection. It should prompt user to select a file path.
35  // Once the selection is made it should asynchronously call
36  // |function_->OnFilePathSelected| with the selection information.
37  // User should be initially suggested to select file named |suggested_name|.
38  // |allowed_extensions| specifies the file extensions allowed to be shown,
39  // and selected. Extensions should not include '.'. This spec comes from
40  // ui::SelectFileDialog() which takes extensions without '.'.
41  //
42  // Selection UI should be displayed using |browser|. |browser| should outlive
43  // the interface implementation.
44  // |function| if the extension function that called the method and needs to
45  // be notified of user action. The interface implementation should keep a
46  // reference to the function until it is notified (extension function
47  // implementations are ref counted).
48  // |SelectFile| will be called at most once by a single extension function.
49  // The interface implementation should delete itself after the extension
50  // function is notified of file selection result.
51  virtual void SelectFile(
52      const base::FilePath& suggested_name,
53      const std::vector<std::string>& allowed_extensions,
54      Browser* browser,
55      FileBrowserHandlerInternalSelectFileFunction* function) = 0;
56};
57
58// Interface that is used by FileBrowserHandlerInternalSelectFileFunction to
59// create a FileSelector it can use to select a file path.
60class FileSelectorFactory {
61 public:
62  virtual ~FileSelectorFactory() {}
63
64  // Creates a FileSelector instance for the
65  // FileBrowserHandlerInternalSelectFileFunction.
66  virtual FileSelector* CreateFileSelector() const = 0;
67};
68
69}  // namespace file_manager
70
71
72// Note that this class is not in 'file_manager' class to be consistent with
73// all other extension functions registered in
74// chrome/common/extensions/api/generated_api.cc being in the global namespace.
75//
76// The fileBrowserHandlerInternal.selectFile extension function implementation.
77// See the file description for more info.
78class FileBrowserHandlerInternalSelectFileFunction
79    : public AsyncExtensionFunction {
80 public:
81  // Default constructor used in production code.
82  // It will create its own FileSelectorFactory implementation, and set the
83  // value of |user_gesture_check_enabled| to true.
84  FileBrowserHandlerInternalSelectFileFunction();
85
86  // This constructor should be used only in tests to inject test file selector
87  // factory and to allow extension function to run even if it hasn't been
88  // invoked by user gesture.
89  // Created object will take the ownership of the |file_selector_factory|.
90  FileBrowserHandlerInternalSelectFileFunction(
91      file_manager::FileSelectorFactory* file_selector_factory,
92      bool enable_user_gesture_check);
93
94  // Called by FileSelector implementation when the user selects the file's
95  // file path. File access permissions for the selected file are granted and
96  // caller is notified of the selection result after this method is called.
97  // |success| Whether the path was selected.
98  // |full_path| The selected file path if one was selected. It is ignored if
99  // the selection did not succeed.
100  void OnFilePathSelected(bool success, const base::FilePath& full_path);
101
102 protected:
103  // The class is ref counted, so destructor should not be public.
104  virtual ~FileBrowserHandlerInternalSelectFileFunction();
105
106  // AsyncExtensionFunction implementation.
107  // Runs the extension function implementation.
108  virtual bool RunImpl() OVERRIDE;
109
110 private:
111  // Called when the external file system is opened for the extension function
112  // caller in the browser context. It saves opened file system's parameters.
113  // The file system is needed to create FileEntry object for the selection
114  // result.
115  // |success| Whether the file system has been opened successfully.
116  // |file_system_name| The file system's name.
117  // |file_system_root| The file system's root url.
118  void OnFileSystemOpened(bool success,
119                          const std::string& file_system_name,
120                          const GURL& file_system_root);
121
122  // Grants file access permissions for the created file to the caller.
123  // Inside this method, |virtual_path_| value is set.
124  void GrantPermissions();
125
126  // Creates dictionary value that will be used to as the extension function's
127  // callback argument and ends extension function execution by calling
128  // |SendResponse(true)|.
129  // The |results_| value will be set to dictionary containing two properties:
130  // * boolean 'success', which will be equal to |success|.
131  // * object 'entry', which will be set only when |success| if true and
132  //   will contain information needed to create a FileEntry object for the
133  //   selected file. It contains following properties:
134  //   * 'file_system_name' set to |file_system_name_|
135  //   * 'file_system_root' set to |file_system_root_|
136  //   * 'file_full_path' set to |virtual_path_| (with leading '/')
137  //   * 'file_is_directory' set to |false|.
138  //   |file_system_name_|, |file_system_root_| and |virtual_path_| are ignored
139  //   if |success| if false.
140  void Respond(bool success);
141
142  // Factory used to create FileSelector to be used for prompting user to select
143  // file.
144  scoped_ptr<file_manager::FileSelectorFactory> file_selector_factory_;
145  // Whether user gesture check is disabled. This should be true only in tests.
146  bool user_gesture_check_enabled_;
147
148  // Full file system path of the selected file.
149  base::FilePath full_path_;
150  // Selected file's virtual path in extension function caller's file system.
151  base::FilePath virtual_path_;
152  // Extension function caller's file system name.
153  std::string file_system_name_;
154  // Extension function caller's file system root URL.
155  GURL file_system_root_;
156
157  // List of permissions and paths that have to be granted for the selected
158  // files.
159  std::vector<std::pair<base::FilePath, int> > permissions_to_grant_;
160
161  DECLARE_EXTENSION_FUNCTION("fileBrowserHandlerInternal.selectFile",
162                             FILEBROWSERHANDLERINTERNAL_SELECTFILE)
163};
164
165#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_FILE_BROWSER_HANDLER_API_H_
166