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

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

Issue 2812773002: Refactor Clipboard Last Modified Time Storage (Closed)
Patch Set: rebase Created 3 years, 8 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_android.h ('k') | ui/base/test/test_clipboard.h » ('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_android.h" 5 #include "ui/base/clipboard/clipboard_android.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/android/context_utils.h" 9 #include "base/android/context_utils.h"
10 #include "base/android/jni_string.h" 10 #include "base/android/jni_string.h"
11 #include "base/android/scoped_java_ref.h"
11 #include "base/lazy_instance.h" 12 #include "base/lazy_instance.h"
12 #include "base/stl_util.h" 13 #include "base/stl_util.h"
13 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
14 #include "base/synchronization/lock.h" 15 #include "base/synchronization/lock.h"
16 #include "base/time/time.h"
15 #include "jni/Clipboard_jni.h" 17 #include "jni/Clipboard_jni.h"
16 #include "third_party/skia/include/core/SkBitmap.h" 18 #include "third_party/skia/include/core/SkBitmap.h"
17 #include "ui/gfx/geometry/size.h" 19 #include "ui/gfx/geometry/size.h"
18 20
19 // TODO:(andrewhayden) Support additional formats in Android: Bitmap, URI, HTML, 21 // TODO:(andrewhayden) Support additional formats in Android: Bitmap, URI, HTML,
20 // HTML+text now that Android's clipboard system supports them, then nuke the 22 // HTML+text now that Android's clipboard system supports them, then nuke the
21 // legacy implementation note below. 23 // legacy implementation note below.
22 24
23 // Legacy implementation note: 25 // Legacy implementation note:
24 // The Android clipboard system used to only support text format. So we used the 26 // The Android clipboard system used to only support text format. So we used the
25 // Android system when some text was added or retrieved from the system. For 27 // Android system when some text was added or retrieved from the system. For
26 // anything else, we STILL store the value in some process wide static 28 // anything else, we STILL store the value in some process wide static
27 // variable protected by a lock. So the (non-text) clipboard will only work 29 // variable protected by a lock. So the (non-text) clipboard will only work
28 // within the same process. 30 // within the same process.
29 31
30 using base::android::AttachCurrentThread; 32 using base::android::AttachCurrentThread;
31 using base::android::ClearException; 33 using base::android::ClearException;
32 using base::android::ConvertJavaStringToUTF8; 34 using base::android::ConvertJavaStringToUTF8;
33 using base::android::ConvertUTF8ToJavaString; 35 using base::android::ConvertUTF8ToJavaString;
34 using base::android::ScopedJavaGlobalRef; 36 using base::android::ScopedJavaGlobalRef;
35 using base::android::ScopedJavaLocalRef; 37 using base::android::ScopedJavaLocalRef;
36 38
37 namespace ui { 39 namespace ui {
38 40
39 namespace { 41 namespace {
42
40 // Various formats we support. 43 // Various formats we support.
41 const char kURLFormat[] = "url"; 44 const char kURLFormat[] = "url";
42 const char kPlainTextFormat[] = "text"; 45 const char kPlainTextFormat[] = "text";
43 const char kHTMLFormat[] = "html"; 46 const char kHTMLFormat[] = "html";
44 const char kRTFFormat[] = "rtf"; 47 const char kRTFFormat[] = "rtf";
45 const char kBitmapFormat[] = "bitmap"; 48 const char kBitmapFormat[] = "bitmap";
46 const char kWebKitSmartPasteFormat[] = "webkit_smart"; 49 const char kWebKitSmartPasteFormat[] = "webkit_smart";
47 const char kBookmarkFormat[] = "bookmark"; 50 const char kBookmarkFormat[] = "bookmark";
48 51
49 class ClipboardMap { 52 class ClipboardMap {
50 public: 53 public:
51 ClipboardMap(); 54 ClipboardMap();
52 std::string Get(const std::string& format); 55 std::string Get(const std::string& format);
53 int64_t GetLastClipboardChangeTimeInMillis(); 56 uint64_t GetSequenceNumber() const;
57 base::Time GetLastModifiedTime() const;
58 void ClearLastModifiedTime();
54 bool HasFormat(const std::string& format); 59 bool HasFormat(const std::string& format);
60 void OnPrimaryClipboardChanged();
55 void Set(const std::string& format, const std::string& data); 61 void Set(const std::string& format, const std::string& data);
56 void CommitToAndroidClipboard(); 62 void CommitToAndroidClipboard();
57 void Clear(); 63 void Clear();
58 64
59 private: 65 private:
60 void UpdateFromAndroidClipboard(); 66 void UpdateFromAndroidClipboard();
61 std::map<std::string, std::string> map_; 67 std::map<std::string, std::string> map_;
68 bool map_up_to_date_;
62 base::Lock lock_; 69 base::Lock lock_;
63 70
64 int64_t last_clipboard_change_time_ms_; 71 uint64_t sequence_number_;
72 base::Time last_modified_time_;
65 73
66 // Java class and methods for the Android ClipboardManager. 74 // Java class and methods for the Android ClipboardManager.
67 ScopedJavaGlobalRef<jobject> clipboard_manager_; 75 ScopedJavaGlobalRef<jobject> clipboard_manager_;
68 }; 76 };
69 base::LazyInstance<ClipboardMap>::Leaky g_map = LAZY_INSTANCE_INITIALIZER; 77 base::LazyInstance<ClipboardMap>::Leaky g_map = LAZY_INSTANCE_INITIALIZER;
70 78
71 ClipboardMap::ClipboardMap() { 79 ClipboardMap::ClipboardMap() {
72 clipboard_manager_.Reset(Java_Clipboard_getInstance(AttachCurrentThread())); 80 clipboard_manager_.Reset(Java_Clipboard_getInstance(AttachCurrentThread()));
73 DCHECK(clipboard_manager_.obj()); 81 DCHECK(clipboard_manager_.obj());
82 map_up_to_date_ = false;
dcheng 2017/04/13 20:35:37 Nit: use the initializer list (or use in-class ini
Mark P 2017/04/13 20:54:05 Done.
74 } 83 }
75 84
76 std::string ClipboardMap::Get(const std::string& format) { 85 std::string ClipboardMap::Get(const std::string& format) {
77 base::AutoLock lock(lock_); 86 base::AutoLock lock(lock_);
78 UpdateFromAndroidClipboard(); 87 UpdateFromAndroidClipboard();
79 std::map<std::string, std::string>::const_iterator it = map_.find(format); 88 std::map<std::string, std::string>::const_iterator it = map_.find(format);
80 return it == map_.end() ? std::string() : it->second; 89 return it == map_.end() ? std::string() : it->second;
81 } 90 }
82 91
83 int64_t ClipboardMap::GetLastClipboardChangeTimeInMillis() { 92 uint64_t ClipboardMap::GetSequenceNumber() const {
84 base::AutoLock lock(lock_); 93 return sequence_number_;
85 UpdateFromAndroidClipboard(); 94 }
86 return last_clipboard_change_time_ms_; 95
96 base::Time ClipboardMap::GetLastModifiedTime() const {
97 return last_modified_time_;
98 }
99
100 void ClipboardMap::ClearLastModifiedTime() {
101 last_modified_time_ = base::Time();
87 } 102 }
88 103
89 bool ClipboardMap::HasFormat(const std::string& format) { 104 bool ClipboardMap::HasFormat(const std::string& format) {
90 base::AutoLock lock(lock_); 105 base::AutoLock lock(lock_);
91 UpdateFromAndroidClipboard(); 106 UpdateFromAndroidClipboard();
92 return base::ContainsKey(map_, format); 107 return base::ContainsKey(map_, format);
93 } 108 }
94 109
110 void ClipboardMap::OnPrimaryClipboardChanged() {
111 sequence_number_++;
112 last_modified_time_ = base::Time::Now();
113 map_up_to_date_ = false;
114 }
115
95 void ClipboardMap::Set(const std::string& format, const std::string& data) { 116 void ClipboardMap::Set(const std::string& format, const std::string& data) {
96 base::AutoLock lock(lock_); 117 base::AutoLock lock(lock_);
97 map_[format] = data; 118 map_[format] = data;
119 map_up_to_date_ = false;
dcheng 2017/04/13 20:35:37 Can we make this a tri-state enum? Calling UpdateF
Mark P 2017/04/13 20:54:05 Do you mean MAP_OUT_OF_DATE MAP_FRESHER_THAN_JAVA
dcheng 2017/04/13 20:59:18 MAP_OUT_OF_DATE MAP_UP_TO_DATE MAP_PREPARING_COMMI
Mark P 2017/04/13 21:21:46 Done with the scoped enum. Please take a look. T
98 } 120 }
99 121
100 void ClipboardMap::CommitToAndroidClipboard() { 122 void ClipboardMap::CommitToAndroidClipboard() {
101 JNIEnv* env = AttachCurrentThread(); 123 JNIEnv* env = AttachCurrentThread();
102 base::AutoLock lock(lock_); 124 base::AutoLock lock(lock_);
103 if (base::ContainsKey(map_, kHTMLFormat)) { 125 if (base::ContainsKey(map_, kHTMLFormat)) {
104 // Android's API for storing HTML content on the clipboard requires a plain- 126 // Android's API for storing HTML content on the clipboard requires a plain-
105 // text representation to be available as well. 127 // text representation to be available as well.
106 if (!base::ContainsKey(map_, kPlainTextFormat)) 128 if (!base::ContainsKey(map_, kPlainTextFormat))
107 return; 129 return;
108 130
109 ScopedJavaLocalRef<jstring> html = 131 ScopedJavaLocalRef<jstring> html =
110 ConvertUTF8ToJavaString(env, map_[kHTMLFormat]); 132 ConvertUTF8ToJavaString(env, map_[kHTMLFormat]);
111 ScopedJavaLocalRef<jstring> text = 133 ScopedJavaLocalRef<jstring> text =
112 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]); 134 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]);
113 135
114 DCHECK(html.obj() && text.obj()); 136 DCHECK(html.obj() && text.obj());
115 Java_Clipboard_setHTMLText(env, clipboard_manager_, html, text); 137 Java_Clipboard_setHTMLText(env, clipboard_manager_, html, text);
116 } else if (base::ContainsKey(map_, kPlainTextFormat)) { 138 } else if (base::ContainsKey(map_, kPlainTextFormat)) {
117 ScopedJavaLocalRef<jstring> str = 139 ScopedJavaLocalRef<jstring> str =
118 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]); 140 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]);
119 DCHECK(str.obj()); 141 DCHECK(str.obj());
120 Java_Clipboard_setText(env, clipboard_manager_, str); 142 Java_Clipboard_setText(env, clipboard_manager_, str);
121 } else { 143 } else {
122 Java_Clipboard_clear(env, clipboard_manager_); 144 Java_Clipboard_clear(env, clipboard_manager_);
123 NOTIMPLEMENTED(); 145 NOTIMPLEMENTED();
124 } 146 }
147 map_up_to_date_ = true;
148 sequence_number_++;
149 last_modified_time_ = base::Time::Now();
125 } 150 }
126 151
127 void ClipboardMap::Clear() { 152 void ClipboardMap::Clear() {
128 JNIEnv* env = AttachCurrentThread(); 153 JNIEnv* env = AttachCurrentThread();
129 base::AutoLock lock(lock_); 154 base::AutoLock lock(lock_);
130 map_.clear(); 155 map_.clear();
131 Java_Clipboard_clear(env, clipboard_manager_); 156 Java_Clipboard_clear(env, clipboard_manager_);
157 map_up_to_date_ = true;
158 sequence_number_++;
159 last_modified_time_ = base::Time::Now();
132 } 160 }
133 161
134 // Add a key:jstr pair to map, but only if jstr is not null, and also 162 // Add a key:jstr pair to map, but only if jstr is not null, and also
135 // not empty. 163 // not empty.
136 void AddMapEntry(JNIEnv* env, 164 void AddMapEntry(JNIEnv* env,
137 std::map<std::string, std::string>* map, 165 std::map<std::string, std::string>* map,
138 const char* key, 166 const char* key,
139 const ScopedJavaLocalRef<jstring>& jstr) { 167 const ScopedJavaLocalRef<jstring>& jstr) {
140 if (!jstr.is_null()) { 168 if (!jstr.is_null()) {
141 std::string str = ConvertJavaStringToUTF8(env, jstr.obj()); 169 std::string str = ConvertJavaStringToUTF8(env, jstr.obj());
142 if (!str.empty()) 170 if (!str.empty())
143 (*map)[key] = str; 171 (*map)[key] = str;
144 } 172 }
145 } 173 }
146 174
147 // Return true if all the key-value pairs in map1 are also in map2. 175 void ClipboardMap::UpdateFromAndroidClipboard() {
148 bool MapIsSubset(const std::map<std::string, std::string>& map1, 176 if (map_up_to_date_)
149 const std::map<std::string, std::string>& map2) { 177 return;
150 for (const auto& val : map1) {
151 auto iter = map2.find(val.first);
152 if (iter == map2.end() || iter->second != val.second)
153 return false;
154 }
155 return true;
156 }
157 178
158 void ClipboardMap::UpdateFromAndroidClipboard() { 179 // Fetch the current Android clipboard state.
159 // Fetch the current Android clipboard state. Replace our state with
160 // the Android state if the Android state has been changed.
161 lock_.AssertAcquired(); 180 lock_.AssertAcquired();
162 JNIEnv* env = AttachCurrentThread(); 181 JNIEnv* env = AttachCurrentThread();
163 182
164 std::map<std::string, std::string> android_clipboard_state;
165
166 ScopedJavaLocalRef<jstring> jtext = 183 ScopedJavaLocalRef<jstring> jtext =
167 Java_Clipboard_getCoercedText(env, clipboard_manager_); 184 Java_Clipboard_getCoercedText(env, clipboard_manager_);
168 ScopedJavaLocalRef<jstring> jhtml = 185 ScopedJavaLocalRef<jstring> jhtml =
169 Java_Clipboard_getHTMLText(env, clipboard_manager_); 186 Java_Clipboard_getHTMLText(env, clipboard_manager_);
170 187
171 AddMapEntry(env, &android_clipboard_state, kPlainTextFormat, jtext); 188 AddMapEntry(env, &map_, kPlainTextFormat, jtext);
172 AddMapEntry(env, &android_clipboard_state, kHTMLFormat, jhtml); 189 AddMapEntry(env, &map_, kHTMLFormat, jhtml);
173 last_clipboard_change_time_ms_ =
174 Java_Clipboard_getClipboardContentChangeTimeInMillis(env,
175 clipboard_manager_);
176 190
177 if (!MapIsSubset(android_clipboard_state, map_)) 191 map_up_to_date_ = true;
178 android_clipboard_state.swap(map_);
179 } 192 }
180 193
181 } // namespace 194 } // namespace
182 195
183 // Clipboard::FormatType implementation. 196 // Clipboard::FormatType implementation.
184 Clipboard::FormatType::FormatType() { 197 Clipboard::FormatType::FormatType() {
185 } 198 }
186 199
187 Clipboard::FormatType::FormatType(const std::string& native_format) 200 Clipboard::FormatType::FormatType(const std::string& native_format)
188 : data_(native_format) { 201 : data_(native_format) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 return type; 283 return type;
271 } 284 }
272 285
273 // Clipboard factory method. 286 // Clipboard factory method.
274 // static 287 // static
275 Clipboard* Clipboard::Create() { 288 Clipboard* Clipboard::Create() {
276 return new ClipboardAndroid; 289 return new ClipboardAndroid;
277 } 290 }
278 291
279 // ClipboardAndroid implementation. 292 // ClipboardAndroid implementation.
293
294 void ClipboardAndroid::OnPrimaryClipChanged(
295 JNIEnv* env,
296 const base::android::JavaParamRef<jobject>& obj) {
297 g_map.Get().OnPrimaryClipboardChanged();
298 }
299
280 ClipboardAndroid::ClipboardAndroid() { 300 ClipboardAndroid::ClipboardAndroid() {
281 DCHECK(CalledOnValidThread()); 301 DCHECK(CalledOnValidThread());
282 } 302 }
283 303
284 ClipboardAndroid::~ClipboardAndroid() { 304 ClipboardAndroid::~ClipboardAndroid() {
285 DCHECK(CalledOnValidThread()); 305 DCHECK(CalledOnValidThread());
286 } 306 }
287 307
288 void ClipboardAndroid::OnPreShutdown() {} 308 void ClipboardAndroid::OnPreShutdown() {}
289 309
290 uint64_t ClipboardAndroid::GetSequenceNumber(ClipboardType /* type */) const { 310 uint64_t ClipboardAndroid::GetSequenceNumber(ClipboardType /* type */) const {
291 DCHECK(CalledOnValidThread()); 311 DCHECK(CalledOnValidThread());
292 // TODO: implement this. For now this interface will advertise 312 return g_map.Get().GetSequenceNumber();
293 // that the clipboard never changes. That's fine as long as we
294 // don't rely on this signal.
295 return 0;
296 } 313 }
297 314
298 bool ClipboardAndroid::IsFormatAvailable(const Clipboard::FormatType& format, 315 bool ClipboardAndroid::IsFormatAvailable(const Clipboard::FormatType& format,
299 ClipboardType type) const { 316 ClipboardType type) const {
300 DCHECK(CalledOnValidThread()); 317 DCHECK(CalledOnValidThread());
301 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 318 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
302 return g_map.Get().HasFormat(format.ToString()); 319 return g_map.Get().HasFormat(format.ToString());
303 } 320 }
304 321
305 void ClipboardAndroid::Clear(ClipboardType type) { 322 void ClipboardAndroid::Clear(ClipboardType type) {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 DCHECK(CalledOnValidThread()); 424 DCHECK(CalledOnValidThread());
408 NOTIMPLEMENTED(); 425 NOTIMPLEMENTED();
409 } 426 }
410 427
411 void ClipboardAndroid::ReadData(const Clipboard::FormatType& format, 428 void ClipboardAndroid::ReadData(const Clipboard::FormatType& format,
412 std::string* result) const { 429 std::string* result) const {
413 DCHECK(CalledOnValidThread()); 430 DCHECK(CalledOnValidThread());
414 *result = g_map.Get().Get(format.ToString()); 431 *result = g_map.Get().Get(format.ToString());
415 } 432 }
416 433
417 base::Time ClipboardAndroid::GetClipboardLastModifiedTime() const { 434 base::Time ClipboardAndroid::GetLastModifiedTime() const {
418 DCHECK(CalledOnValidThread()); 435 DCHECK(CalledOnValidThread());
419 return base::Time::FromJavaTime( 436 return g_map.Get().GetLastModifiedTime();
420 g_map.Get().GetLastClipboardChangeTimeInMillis()); 437 }
438
439 void ClipboardAndroid::ClearLastModifiedTime() {
440 DCHECK(CalledOnValidThread());
441 g_map.Get().ClearLastModifiedTime();
421 } 442 }
422 443
423 // Main entry point used to write several values in the clipboard. 444 // Main entry point used to write several values in the clipboard.
424 void ClipboardAndroid::WriteObjects(ClipboardType type, 445 void ClipboardAndroid::WriteObjects(ClipboardType type,
425 const ObjectMap& objects) { 446 const ObjectMap& objects) {
426 DCHECK(CalledOnValidThread()); 447 DCHECK(CalledOnValidThread());
427 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 448 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
428 g_map.Get().Clear(); 449 g_map.Get().Clear();
429 450
430 for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end(); 451 for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 } 499 }
479 g_map.Get().Set(kBitmapFormat, packed); 500 g_map.Get().Set(kBitmapFormat, packed);
480 } 501 }
481 502
482 void ClipboardAndroid::WriteData(const Clipboard::FormatType& format, 503 void ClipboardAndroid::WriteData(const Clipboard::FormatType& format,
483 const char* data_data, 504 const char* data_data,
484 size_t data_len) { 505 size_t data_len) {
485 g_map.Get().Set(format.ToString(), std::string(data_data, data_len)); 506 g_map.Get().Set(format.ToString(), std::string(data_data, data_len));
486 } 507 }
487 508
509 bool RegisterClipboardAndroid(JNIEnv* env) {
510 return RegisterNativesImpl(env);
511 }
512
513 // Returns a pointer to the current ClipboardAndroid object.
514 static jlong Init(JNIEnv* env,
515 const base::android::JavaParamRef<jobject>& obj) {
516 return reinterpret_cast<intptr_t>(Clipboard::GetForCurrentThread());
517 }
518
488 } // namespace ui 519 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/clipboard/clipboard_android.h ('k') | ui/base/test/test_clipboard.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698