blob: adf17187f05261439de5a5918afd76d65b350611 [file] [log] [blame]
Avi Drissman3e1a26c2022-09-15 20:26:031// Copyright 2012 The Chromium Authors
[email protected]e8c62b92013-01-16 23:08:272// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "select_file_dialog_android.h"
6
7#include "base/android/jni_android.h"
[email protected]e8c62b92013-01-16 23:08:278#include "base/android/jni_array.h"
[email protected]d778e0422013-03-06 18:10:229#include "base/android/jni_string.h"
[email protected]e8c62b92013-01-16 23:08:2710#include "base/android/scoped_java_ref.h"
Hans Wennborg8586102b2020-05-05 13:43:2911#include "base/check.h"
12#include "base/notreached.h"
[email protected]d778e0422013-03-06 18:10:2213#include "base/strings/string_split.h"
[email protected]3b3a30642013-06-11 19:48:3814#include "base/strings/string_util.h"
[email protected]c7057fbe2013-06-07 18:54:0115#include "base/strings/utf_string_conversions.h"
jaekyune4f9eed2015-02-24 02:06:5816#include "ui/android/window_android.h"
Brett Wilson804e83c2017-08-18 22:57:3317#include "ui/shell_dialogs/select_file_policy.h"
[email protected]f2263352014-02-04 13:09:4118#include "ui/shell_dialogs/selected_file_info.h"
Aida Zolica03ba4ca2022-09-29 13:50:0919#include "url/gurl.h"
[email protected]e8c62b92013-01-16 23:08:2720
Andrew Grieveecb885bb2024-05-29 18:14:1921// Must come after all headers that specialize FromJniType() / ToJniType().
22#include "ui/base/select_file_dialog_jni_headers/SelectFileDialog_jni.h"
23
[email protected]98dd29f2014-08-06 16:04:3524using base::android::ConvertJavaStringToUTF8;
torne86560112016-08-04 15:59:0425using base::android::JavaParamRef;
26using base::android::ScopedJavaLocalRef;
[email protected]98dd29f2014-08-06 16:04:3527
[email protected]e8c62b92013-01-16 23:08:2728namespace ui {
Joel Hockey73d3472f2024-08-14 21:00:5029namespace {
30
31constexpr char kGetContent[] = "android.intent.action.GET_CONTENT";
32constexpr char kOpenDocument[] = "android.intent.action.OPEN_DOCUMENT";
Joel Hockeya7e3f40f2024-10-31 01:22:3233constexpr char kCreateDocument[] = "android.intent.action.CREATE_DOCUMENT";
Joel Hockey73d3472f2024-08-14 21:00:5034constexpr char kOpenDocumentTree[] = "android.intent.action.OPEN_DOCUMENT_TREE";
35
36std::string IntentActionFromType(SelectFileDialog::Type type,
37 bool open_writable) {
38 switch (type) {
39 case SelectFileDialog::SELECT_NONE:
40 return kGetContent;
41 case SelectFileDialog::SELECT_OPEN_FILE:
42 case SelectFileDialog::SELECT_OPEN_MULTI_FILE:
43 return open_writable ? kOpenDocument : kGetContent;
44 case SelectFileDialog::SELECT_SAVEAS_FILE:
Joel Hockeya7e3f40f2024-10-31 01:22:3245 return kCreateDocument;
Joel Hockey73d3472f2024-08-14 21:00:5046 case SelectFileDialog::SELECT_FOLDER:
47 case SelectFileDialog::SELECT_UPLOAD_FOLDER:
48 case SelectFileDialog::SELECT_EXISTING_FOLDER:
49 return kOpenDocumentTree;
50 }
51}
52
53} // namespace
[email protected]e8c62b92013-01-16 23:08:2754
55// static
Brett Wilson804e83c2017-08-18 22:57:3356SelectFileDialogImpl* SelectFileDialogImpl::Create(
57 Listener* listener,
58 std::unique_ptr<SelectFilePolicy> policy) {
59 return new SelectFileDialogImpl(listener, std::move(policy));
[email protected]e8c62b92013-01-16 23:08:2760}
61
tornebb13c832015-12-07 12:49:1462void SelectFileDialogImpl::OnFileSelected(
63 JNIEnv* env,
64 const JavaParamRef<jobject>& java_object,
65 const JavaParamRef<jstring>& filepath,
66 const JavaParamRef<jstring>& display_name) {
[email protected]98dd29f2014-08-06 16:04:3567 if (!listener_)
68 return;
69
70 std::string path = ConvertJavaStringToUTF8(env, filepath);
71 std::string file_name = ConvertJavaStringToUTF8(env, display_name);
72 base::FilePath file_path = base::FilePath(path);
Avi Drissmand0b88a2b2023-12-28 22:49:3873 ui::SelectedFileInfo file_info(file_path);
[email protected]98dd29f2014-08-06 16:04:3574 if (!file_name.empty())
75 file_info.display_name = file_name;
76
Elly Fong-Jones0b8b56222024-07-15 19:53:5377 listener_->FileSelected(file_info, 0);
[email protected]98dd29f2014-08-06 16:04:3578}
79
tornebb13c832015-12-07 12:49:1480void SelectFileDialogImpl::OnMultipleFilesSelected(
81 JNIEnv* env,
82 const JavaParamRef<jobject>& java_object,
83 const JavaParamRef<jobjectArray>& filepaths,
84 const JavaParamRef<jobjectArray>& display_names) {
[email protected]98dd29f2014-08-06 16:04:3585 if (!listener_)
86 return;
87
88 std::vector<ui::SelectedFileInfo> selected_files;
89
90 jsize length = env->GetArrayLength(filepaths);
91 DCHECK(length == env->GetArrayLength(display_names));
92 for (int i = 0; i < length; ++i) {
Ran Ji8a1874632018-01-29 21:04:3693 ScopedJavaLocalRef<jstring> path_ref(
[email protected]98dd29f2014-08-06 16:04:3594 env, static_cast<jstring>(env->GetObjectArrayElement(filepaths, i)));
Ran Ji8a1874632018-01-29 21:04:3695 base::FilePath file_path =
96 base::FilePath(ConvertJavaStringToUTF8(env, path_ref));
97
98 ScopedJavaLocalRef<jstring> display_name_ref(
[email protected]98dd29f2014-08-06 16:04:3599 env,
100 static_cast<jstring>(env->GetObjectArrayElement(display_names, i)));
Ran Ji8a1874632018-01-29 21:04:36101 std::string display_name =
102 ConvertJavaStringToUTF8(env, display_name_ref.obj());
[email protected]98dd29f2014-08-06 16:04:35103
Avi Drissmand0b88a2b2023-12-28 22:49:38104 ui::SelectedFileInfo file_info(file_path);
[email protected]98dd29f2014-08-06 16:04:35105 file_info.display_name = display_name;
106
107 selected_files.push_back(file_info);
[email protected]e8c62b92013-01-16 23:08:27108 }
[email protected]98dd29f2014-08-06 16:04:35109
Elly Fong-Jones0b8b56222024-07-15 19:53:53110 listener_->MultiFilesSelected(selected_files);
[email protected]e8c62b92013-01-16 23:08:27111}
112
113void SelectFileDialogImpl::OnFileNotSelected(
114 JNIEnv* env,
tornebb13c832015-12-07 12:49:14115 const JavaParamRef<jobject>& java_object) {
[email protected]e8c62b92013-01-16 23:08:27116 if (listener_)
Elly Fong-Jones0b8b56222024-07-15 19:53:53117 listener_->FileSelectionCanceled();
[email protected]e8c62b92013-01-16 23:08:27118}
119
120bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow) const {
[email protected]64e82b22014-03-05 00:20:06121 return listener_;
[email protected]e8c62b92013-01-16 23:08:27122}
123
124void SelectFileDialogImpl::ListenerDestroyed() {
Bartek Nowierskic740c76c2020-06-15 02:32:44125 listener_ = nullptr;
[email protected]e8c62b92013-01-16 23:08:27126}
127
Elly0a2ac342024-07-03 22:38:57128void SelectFileDialogImpl::SetAcceptTypes(std::vector<std::u16string> types) {
129 accept_types_ = std::move(types);
130}
131
132void SelectFileDialogImpl::SetUseMediaCapture(bool use_media_capture) {
133 use_media_capture_ = use_media_capture;
134}
135
Joel Hockey73d3472f2024-08-14 21:00:50136void SelectFileDialogImpl::SetOpenWritable(bool open_writable) {
137 open_writable_ = open_writable;
138}
139
[email protected]e8c62b92013-01-16 23:08:27140void SelectFileDialogImpl::SelectFileImpl(
[email protected]0b59171c2013-06-04 08:38:38141 SelectFileDialog::Type type,
Jan Wilken Dörrie52639572021-03-11 16:49:54142 const std::u16string& title,
[email protected]79f63882013-02-10 05:15:45143 const base::FilePath& default_path,
[email protected]e8c62b92013-01-16 23:08:27144 const SelectFileDialog::FileTypeInfo* file_types,
145 int file_type_index,
146 const std::string& default_extension,
147 gfx::NativeWindow owning_window,
Aida Zolica03ba4ca2022-09-29 13:50:09148 const GURL* caller) {
[email protected]e8c62b92013-01-16 23:08:27149 JNIEnv* env = base::android::AttachCurrentThread();
150
Joel Hockey73d3472f2024-08-14 21:00:50151 ScopedJavaLocalRef<jstring> intent_action =
152 base::android::ConvertUTF8ToJavaString(
153 env, IntentActionFromType(type, open_writable_));
[email protected]e8c62b92013-01-16 23:08:27154 ScopedJavaLocalRef<jobjectArray> accept_types_java =
Elly0a2ac342024-07-03 22:38:57155 base::android::ToJavaArrayOfStrings(env, accept_types_);
[email protected]e8c62b92013-01-16 23:08:27156
[email protected]98dd29f2014-08-06 16:04:35157 bool accept_multiple_files = SelectFileDialog::SELECT_OPEN_MULTI_FILE == type;
158
Joel Hockey71479d1f32024-11-18 23:07:02159 base::FilePath default_directory;
160 base::FilePath suggested_name;
161 // If default_path ends with a separator, then suggested_name was empty.
162 if (default_path.EndsWithSeparator()) {
163 default_directory = default_path;
164 } else {
165 default_directory = default_path.DirName();
166 suggested_name = default_path.BaseName();
167 }
168 if (!default_directory.IsContentUri()) {
169 default_directory = base::FilePath();
170 }
171
Joel Hockey73d3472f2024-08-14 21:00:50172 Java_SelectFileDialog_selectFile(
173 env, java_object_, intent_action, accept_types_java, use_media_capture_,
Joel Hockey71479d1f32024-11-18 23:07:02174 accept_multiple_files, default_directory.value(), suggested_name.value(),
175 owning_window->GetJavaObject());
[email protected]e8c62b92013-01-16 23:08:27176}
177
[email protected]e8c62b92013-01-16 23:08:27178SelectFileDialogImpl::~SelectFileDialogImpl() {
Bo Liu9a899662023-06-09 19:00:04179 JNIEnv* env = base::android::AttachCurrentThread();
180 Java_SelectFileDialog_nativeDestroyed(env, java_object_);
[email protected]e8c62b92013-01-16 23:08:27181}
182
Brett Wilson804e83c2017-08-18 22:57:33183SelectFileDialogImpl::SelectFileDialogImpl(
184 Listener* listener,
185 std::unique_ptr<SelectFilePolicy> policy)
186 : SelectFileDialog(listener, std::move(policy)) {
[email protected]e8c62b92013-01-16 23:08:27187 JNIEnv* env = base::android::AttachCurrentThread();
Luciano Pacheco270245f2022-09-26 19:31:34188 // TODO(crbug.com/1365766): The `intptr_t` to `this` might get stale.
[email protected]e8c62b92013-01-16 23:08:27189 java_object_.Reset(
[email protected]cfccf262013-11-11 23:27:54190 Java_SelectFileDialog_create(env, reinterpret_cast<intptr_t>(this)));
[email protected]e8c62b92013-01-16 23:08:27191}
192
193bool SelectFileDialogImpl::HasMultipleFileTypeChoicesImpl() {
194 NOTIMPLEMENTED();
195 return false;
196}
197
Brett Wilson804e83c2017-08-18 22:57:33198SelectFileDialog* CreateSelectFileDialog(
199 SelectFileDialog::Listener* listener,
200 std::unique_ptr<SelectFilePolicy> policy) {
201 return SelectFileDialogImpl::Create(listener, std::move(policy));
[email protected]e8c62b92013-01-16 23:08:27202}
203
204} // namespace ui