Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1104)

Side by Side Diff: ui/base/clipboard/clipboard_android.cc

Issue 10695051: Upstream the Android clipboard implementation (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/base/clipboard/clipboard.h ('k') | ui/base/clipboard/clipboard_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/base/clipboard/clipboard.h" 5 #include "ui/base/clipboard/clipboard.h"
6 6
7 #include "base/android/jni_string.h"
8 #include "base/lazy_instance.h"
9 #include "base/synchronization/lock.h"
10 #include "base/utf_string_conversions.h"
7 #include "third_party/skia/include/core/SkBitmap.h" 11 #include "third_party/skia/include/core/SkBitmap.h"
8 #include "ui/gfx/size.h" 12 #include "ui/gfx/size.h"
9 13
14 // Important note:
15 // The Android clipboard system only supports text format. So we use the
16 // Android system when some text is added or retrieved from the system. For
17 // anything else, we currently store the value in some process wide static
18 // variable protected by a lock. So the (non-text) clipboard will only work
19 // within the same process.
20
21 using base::android::AttachCurrentThread;
22 using base::android::CheckException;
23 using base::android::ClearException;
24 using base::android::ConvertJavaStringToUTF16;
25 using base::android::ConvertJavaStringToUTF8;
26 using base::android::GetClass;
27 using base::android::GetMethodID;
28 using base::android::ScopedJavaLocalRef;
29
10 namespace ui { 30 namespace ui {
11 31
12 namespace { 32 namespace {
13 33 // Various formats we support.
14 // Various format we support.
15 const char kPlainTextFormat[] = "text"; 34 const char kPlainTextFormat[] = "text";
16 const char kHTMLFormat[] = "html"; 35 const char kHTMLFormat[] = "html";
17 const char kRTFFormat[] = "rtf"; 36 const char kRTFFormat[] = "rtf";
18 const char kBitmapFormat[] = "bitmap"; 37 const char kBitmapFormat[] = "bitmap";
19 const char kWebKitSmartPasteFormat[] = "webkit_smart"; 38 const char kWebKitSmartPasteFormat[] = "webkit_smart";
20 const char kBookmarkFormat[] = "bookmark"; 39 const char kBookmarkFormat[] = "bookmark";
21 const char kMimeTypeWebCustomData[] = "chromium/x-web-custom-data"; 40 const char kMimeTypeWebCustomData[] = "chromium/x-web-custom-data";
22 41
42 class ClipboardMap {
43 public:
dcheng 2012/06/30 03:28:42 1-space indent for public/private
cjhopman 2012/07/02 17:29:11 Done.
44 ClipboardMap();
dcheng 2012/06/30 03:28:42 2 spaces, etc.
cjhopman 2012/07/02 17:29:11 Done.
45 std::string Get(const std::string& format);
46 bool HasFormat(const std::string& format);
47 void Set(const std::string& format, const std::string& data);
48 void Clear();
49
50 private:
51 void ValidateWithLock();
52 std::map<std::string, std::string> map_;
53 base::Lock lock_;
54
55 // Java class and methods for the Android ClipboardManager.
56 base::android::ScopedJavaGlobalRef<jobject> clipboard_manager_;
57 jmethodID set_text_;
58 jmethodID get_text_;
59 jmethodID to_string_;
60 };
61 base::LazyInstance<ClipboardMap>::Leaky g_map = LAZY_INSTANCE_INITIALIZER;
62
63 ClipboardMap::ClipboardMap() {
64 JNIEnv* env = AttachCurrentThread();
65 DCHECK(env);
66
67 // Get the context.
68 jobject context = base::android::GetApplicationContext();
69 DCHECK(context);
70
71 // Get the context class.
72 ScopedJavaLocalRef<jclass> context_class =
73 GetClass(env, "android/content/Context");
74
75 // Get the system service method.
76 jmethodID get_system_service = GetMethodID(env, context_class,
77 "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
78
79 // Retrieve the system service.
80 ScopedJavaLocalRef<jstring> service_name(env, env->NewStringUTF("clipboard"));
81 clipboard_manager_.Reset(env, env->CallObjectMethod(context,
82 get_system_service, service_name.obj()));
83 DCHECK(clipboard_manager_.obj() && !ClearException(env));
84
85 // Retain a few methods we'll keep using.
86 ScopedJavaLocalRef<jclass> clipboard_class =
87 GetClass(env, "android/text/ClipboardManager");
88 set_text_ = GetMethodID(env, clipboard_class,
89 "setText", "(Ljava/lang/CharSequence;)V");
90 get_text_ = GetMethodID(env, clipboard_class,
91 "getText", "()Ljava/lang/CharSequence;");
92
93 // Will need to call toString as CharSequence is not always a String.
94 ScopedJavaLocalRef<jclass> charsequence_class =
95 GetClass(env, "java/lang/CharSequence");
96 to_string_ = GetMethodID(env, charsequence_class,
97 "toString", "()Ljava/lang/String;");
98 }
99
100 std::string ClipboardMap::Get(const std::string& format) {
101 base::AutoLock lock(lock_);
102 ValidateWithLock();
103 return map_[format];
104 }
105
106 bool ClipboardMap::HasFormat(const std::string& format) {
107 return !Get(format).empty();
dcheng 2012/06/30 03:28:42 Consider using ContainsKey() from base/stl_util.h
cjhopman 2012/07/02 17:29:11 Added a comment to clarify. In addition, in Get()
dcheng 2012/07/02 20:22:30 We should use find(). Get() shouldn't mutate the m
cjhopman 2012/07/02 21:00:49 Currently, the Validate() call can also mutate the
dcheng 2012/07/02 21:09:52 Oh right, I forgot about Validate(). I would prefe
cjhopman 2012/07/02 22:33:25 Done. Required small change to Validate/Sync since
108 }
109
110 void ClipboardMap::Set(const std::string& format, const std::string& data) {
111 JNIEnv* env = AttachCurrentThread();
112 base::AutoLock lock(lock_);
113 ValidateWithLock();
114
115 map_[format] = data;
116 if (format == kPlainTextFormat) {
117 ScopedJavaLocalRef<jstring> str(
118 env, env->NewStringUTF(data.c_str()));
119 DCHECK(str.obj() && !ClearException(env));
120 env->CallVoidMethod(clipboard_manager_.obj(), set_text_, str.obj());
121 }
122 }
123
124 void ClipboardMap::Clear() {
125 JNIEnv* env = AttachCurrentThread();
126 base::AutoLock lock(lock_);
127 map_.clear();
128 env->CallVoidMethod(clipboard_manager_.obj(), set_text_, NULL);
129 }
130
131 void ClipboardMap::ValidateWithLock() {
132 lock_.AssertAcquired();
133
134 JNIEnv* env = AttachCurrentThread();
135 ScopedJavaLocalRef<jobject> char_seq_text(
136 env, env->CallObjectMethod(clipboard_manager_.obj(), get_text_));
137 if (char_seq_text.is_null()) {
138 map_.clear();
139 return;
140 }
141
142 std::string internal_string = map_[kPlainTextFormat];
dcheng 2012/06/30 03:28:42 You could use a const ref here to avoid a copy.
cjhopman 2012/07/02 17:29:11 Done.
143 ScopedJavaLocalRef<jstring> tmp_string(env,
144 static_cast<jstring>(env->CallObjectMethod(char_seq_text.obj(),
145 to_string_)));
146 std::string android_string = ConvertJavaStringToUTF8(tmp_string);
147 if (internal_string != android_string) {
148 map_.clear();
149 map_[kPlainTextFormat] = android_string;
150 }
151 }
152
23 } // namespace 153 } // namespace
24 154
25 Clipboard::FormatType::FormatType() { 155 Clipboard::FormatType::FormatType() {
26 } 156 }
27 157
28 Clipboard::FormatType::FormatType(const std::string& native_format) 158 Clipboard::FormatType::FormatType(const std::string& native_format)
29 : data_(native_format) { 159 : data_(native_format) {
30 } 160 }
31 161
32 Clipboard::FormatType::~FormatType() { 162 Clipboard::FormatType::~FormatType() {
33 } 163 }
34 164
35 std::string Clipboard::FormatType::Serialize() const { 165 std::string Clipboard::FormatType::Serialize() const {
36 return data_; 166 return data_;
37 } 167 }
38 168
39 // static 169 // static
40 Clipboard::FormatType Clipboard::FormatType::Deserialize( 170 Clipboard::FormatType Clipboard::FormatType::Deserialize(
41 const std::string& serialization) { 171 const std::string& serialization) {
42 return FormatType(serialization); 172 return FormatType(serialization);
43 } 173 }
44 174
45 bool Clipboard::FormatType::Equals(const FormatType& other) const { 175 bool Clipboard::FormatType::Equals(const FormatType& other) const {
46 return data_ == other.data_; 176 return data_ == other.data_;
47 } 177 }
48 178
49 Clipboard::Clipboard() : set_text_(NULL), has_text_(NULL), get_text_(NULL) { 179 Clipboard::Clipboard() {
50 } 180 }
51 181
52 Clipboard::~Clipboard() { 182 Clipboard::~Clipboard() {
53 } 183 }
54 184
185 // Main entry point used to write several values in the clipboard.
55 void Clipboard::WriteObjects(Buffer buffer, const ObjectMap& objects) { 186 void Clipboard::WriteObjects(Buffer buffer, const ObjectMap& objects) {
187 g_map.Get().Clear();
188 for (ObjectMap::const_iterator iter = objects.begin();
189 iter != objects.end(); ++iter) {
190 DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
191 }
56 } 192 }
57 193
58 uint64 Clipboard::GetSequenceNumber(Clipboard::Buffer /* buffer */) { 194 uint64 Clipboard::GetSequenceNumber(Clipboard::Buffer /* buffer */) {
195 // TODO: implement this. For now this interface will advertise
196 // that the clipboard never changes. That's fine as long as we
197 // don't rely on this signal.
59 return 0; 198 return 0;
60 } 199 }
61 200
62 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, 201 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format,
63 Clipboard::Buffer buffer) const { 202 Clipboard::Buffer buffer) const {
64 return false; 203 DCHECK_EQ(buffer, BUFFER_STANDARD);
204 return g_map.Get().HasFormat(format.data());
65 } 205 }
66 206
67 void Clipboard::Clear(Buffer buffer) { 207 void Clipboard::Clear(Buffer buffer) {
68 208 DCHECK_EQ(buffer, BUFFER_STANDARD);
209 g_map.Get().Clear();
69 } 210 }
70 211
71 void Clipboard::ReadAvailableTypes(Buffer buffer, std::vector<string16>* types, 212 void Clipboard::ReadAvailableTypes(Buffer buffer, std::vector<string16>* types,
72 bool* contains_filenames) const { 213 bool* contains_filenames) const {
214 DCHECK_EQ(buffer, BUFFER_STANDARD);
215
216 if (!types || !contains_filenames) {
217 NOTREACHED();
218 return;
219 }
220
221 NOTIMPLEMENTED();
222
223 types->clear();
224 *contains_filenames = false;
73 } 225 }
74 226
75 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const { 227 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const {
228 std::string utf8;
229 ReadAsciiText(buffer, &utf8);
230 *result = UTF8ToUTF16(utf8);
76 } 231 }
77 232
78 void Clipboard::ReadAsciiText(Clipboard::Buffer buffer, 233 void Clipboard::ReadAsciiText(Clipboard::Buffer buffer,
79 std::string* result) const { 234 std::string* result) const {
235 DCHECK_EQ(buffer, BUFFER_STANDARD);
236 *result = g_map.Get().Get(kPlainTextFormat);
80 } 237 }
81 238
239 // Note: |src_url| isn't really used. It is only implemented in Windows
82 void Clipboard::ReadHTML(Clipboard::Buffer buffer, 240 void Clipboard::ReadHTML(Clipboard::Buffer buffer,
83 string16* markup, 241 string16* markup,
84 std::string* src_url, 242 std::string* src_url,
85 uint32* fragment_start, 243 uint32* fragment_start,
86 uint32* fragment_end) const { 244 uint32* fragment_end) const {
245 if (src_url)
246 src_url->clear();
247 *fragment_start = 0;
248
249 std::string input = g_map.Get().Get(kHTMLFormat);
250
251 *fragment_end = static_cast<uint32>(input.length());
dcheng 2012/06/30 03:28:42 This should be markup->length() after the conversi
cjhopman 2012/07/02 17:29:11 Done.
252 *markup = UTF8ToUTF16(input);
87 } 253 }
88 254
89 void Clipboard::ReadRTF(Buffer buffer, std::string* result) const { 255 void Clipboard::ReadRTF(Buffer buffer, std::string* result) const {
256 NOTIMPLEMENTED();
90 } 257 }
91 258
92 SkBitmap Clipboard::ReadImage(Buffer buffer) const { 259 SkBitmap Clipboard::ReadImage(Buffer buffer) const {
93 return SkBitmap(); 260 std::string input = g_map.Get().Get(kBitmapFormat);
261
262 SkBitmap bmp;
263 if (!input.empty()) {
264 DCHECK_LE(sizeof(gfx::Size), input.size());
265 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(input.c_str());
266
267 bmp.setConfig(
268 SkBitmap::kARGB_8888_Config, size->width(), size->height(), 0);
269 bmp.allocPixels();
270
271 int bm_size = size->width() * size->height() * 4;
272 DCHECK_EQ(sizeof(gfx::Size) + bm_size, input.size());
273
274 memcpy(bmp.getPixels(), input.c_str() + sizeof(gfx::Size), bm_size);
275 }
276 return bmp;
94 } 277 }
95 278
96 void Clipboard::ReadCustomData(Buffer buffer, 279 void Clipboard::ReadCustomData(Buffer buffer,
97 const string16& type, 280 const string16& type,
98 string16* result) const { 281 string16* result) const {
282 NOTIMPLEMENTED();
99 } 283 }
100 284
101 void Clipboard::ReadBookmark(string16* title, std::string* url) const { 285 void Clipboard::ReadBookmark(string16* title, std::string* url) const {
286 NOTIMPLEMENTED();
102 } 287 }
103 288
104 void Clipboard::ReadData(const Clipboard::FormatType& format, 289 void Clipboard::ReadData(const Clipboard::FormatType& format,
105 std::string* result) const { 290 std::string* result) const {
291 *result = g_map.Get().Get(format.data());
106 } 292 }
107 293
108 // static 294 // static
109 Clipboard::FormatType Clipboard::GetFormatType( 295 Clipboard::FormatType Clipboard::GetFormatType(
110 const std::string& format_string) { 296 const std::string& format_string) {
111 return FormatType::Deserialize(format_string); 297 return FormatType::Deserialize(format_string);
112 } 298 }
113 299
114 // static 300 // static
115 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() { 301 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 return type; 333 return type;
148 } 334 }
149 335
150 // static 336 // static
151 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() { 337 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
152 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); 338 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
153 return type; 339 return type;
154 } 340 }
155 341
156 void Clipboard::WriteText(const char* text_data, size_t text_len) { 342 void Clipboard::WriteText(const char* text_data, size_t text_len) {
343 g_map.Get().Set(kPlainTextFormat, std::string(text_data, text_len));
157 } 344 }
158 345
159 void Clipboard::WriteHTML(const char* markup_data, 346 void Clipboard::WriteHTML(const char* markup_data,
160 size_t markup_len, 347 size_t markup_len,
161 const char* url_data, 348 const char* url_data,
162 size_t url_len) { 349 size_t url_len) {
350 static const char* html_prefix = "<meta http-equiv=\"content-type\" "
dcheng 2012/06/30 03:28:42 Do you actually need this? Since only Android Chro
cjhopman 2012/07/02 17:29:11 Done.
351 "content=\"text/html; charset=utf-8\">";
352 g_map.Get().Set(
353 kHTMLFormat, html_prefix + std::string(markup_data, markup_len));
163 } 354 }
164 355
165 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) { 356 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
357 NOTIMPLEMENTED();
166 } 358 }
167 359
360 // Note: according to other platforms implementations, this really writes the
361 // URL spec.
168 void Clipboard::WriteBookmark(const char* title_data, size_t title_len, 362 void Clipboard::WriteBookmark(const char* title_data, size_t title_len,
169 const char* url_data, size_t url_len) { 363 const char* url_data, size_t url_len) {
364 g_map.Get().Set(kBookmarkFormat, std::string(url_data, url_len));
170 } 365 }
171 366
367 // Write an extra flavor that signifies WebKit was the last to modify the
368 // pasteboard. This flavor has no data.
172 void Clipboard::WriteWebSmartPaste() { 369 void Clipboard::WriteWebSmartPaste() {
370 g_map.Get().Set(kWebKitSmartPasteFormat, std::string(""));
dcheng 2012/06/30 03:28:42 std::string() instead of std::string("")
cjhopman 2012/07/02 17:29:11 Done.
173 } 371 }
174 372
373 // All platforms use gfx::Size for size data but it is passed as a const char*
374 // Further, pixel_data is expected to be 32 bits per pixel
375 // Note: we implement this to pass all unit tests but it is currently unclear
376 // how some code would consume this.
175 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) { 377 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) {
378 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data);
379 int bm_size = size->width() * size->height() * 4;
380
381 std::string packed(size_data, sizeof(gfx::Size));
382 packed += std::string(pixel_data, bm_size);
383 g_map.Get().Set(kBitmapFormat, packed);
176 } 384 }
177 385
178 void Clipboard::WriteData(const Clipboard::FormatType& format, 386 void Clipboard::WriteData(const Clipboard::FormatType& format,
179 const char* data_data, size_t data_len) { 387 const char* data_data, size_t data_len) {
388 g_map.Get().Set(format.data(), std::string(data_data, data_len));
180 } 389 }
181 390
182 bool Clipboard::IsTextAvailableFromAndroid() const { 391 } // namespace ui
183 return false;
184 }
185
186 void Clipboard::ValidateInternalClipboard() const {
187 }
188
189 void Clipboard::Clear() {
190 }
191
192 void Clipboard::ClearInternalClipboard() const {
193 }
194
195 void Clipboard::Set(const std::string& key, const std::string& value) {
196 }
197
198 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/clipboard/clipboard.h ('k') | ui/base/clipboard/clipboard_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698