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

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

Issue 2812773002: Refactor Clipboard Last Modified Time Storage (Closed)
Patch Set: load on startup 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
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"
17 #include "components/prefs/pref_registry_simple.h"
15 #include "jni/Clipboard_jni.h" 18 #include "jni/Clipboard_jni.h"
16 #include "third_party/skia/include/core/SkBitmap.h" 19 #include "third_party/skia/include/core/SkBitmap.h"
17 #include "ui/gfx/geometry/size.h" 20 #include "ui/gfx/geometry/size.h"
18 21
19 // TODO:(andrewhayden) Support additional formats in Android: Bitmap, URI, HTML, 22 // TODO:(andrewhayden) Support additional formats in Android: Bitmap, URI, HTML,
20 // HTML+text now that Android's clipboard system supports them, then nuke the 23 // HTML+text now that Android's clipboard system supports them, then nuke the
21 // legacy implementation note below. 24 // legacy implementation note below.
22 25
23 // Legacy implementation note: 26 // Legacy implementation note:
24 // The Android clipboard system used to only support text format. So we used the 27 // 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 28 // 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 29 // 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 30 // variable protected by a lock. So the (non-text) clipboard will only work
28 // within the same process. 31 // within the same process.
29 32
30 using base::android::AttachCurrentThread; 33 using base::android::AttachCurrentThread;
31 using base::android::ClearException; 34 using base::android::ClearException;
32 using base::android::ConvertJavaStringToUTF8; 35 using base::android::ConvertJavaStringToUTF8;
33 using base::android::ConvertUTF8ToJavaString; 36 using base::android::ConvertUTF8ToJavaString;
34 using base::android::ScopedJavaGlobalRef; 37 using base::android::ScopedJavaGlobalRef;
35 using base::android::ScopedJavaLocalRef; 38 using base::android::ScopedJavaLocalRef;
36 39
37 namespace ui { 40 namespace ui {
38 41
39 namespace { 42 namespace {
43
44 const char kClipboardLastModifiedTimePref[] = "ui.clipboard.last_modified_time";
45
40 // Various formats we support. 46 // Various formats we support.
41 const char kURLFormat[] = "url"; 47 const char kURLFormat[] = "url";
42 const char kPlainTextFormat[] = "text"; 48 const char kPlainTextFormat[] = "text";
43 const char kHTMLFormat[] = "html"; 49 const char kHTMLFormat[] = "html";
44 const char kRTFFormat[] = "rtf"; 50 const char kRTFFormat[] = "rtf";
45 const char kBitmapFormat[] = "bitmap"; 51 const char kBitmapFormat[] = "bitmap";
46 const char kWebKitSmartPasteFormat[] = "webkit_smart"; 52 const char kWebKitSmartPasteFormat[] = "webkit_smart";
47 const char kBookmarkFormat[] = "bookmark"; 53 const char kBookmarkFormat[] = "bookmark";
48 54
49 class ClipboardMap { 55 class ClipboardMap {
50 public: 56 public:
51 ClipboardMap(); 57 ClipboardMap();
52 std::string Get(const std::string& format); 58 std::string Get(const std::string& format);
53 int64_t GetLastClipboardChangeTimeInMillis(); 59 uint64_t GetSequenceNumber() const;
60 base::Time GetClipboardLastModifiedTime() const;
61 void ClearClipboardLastModifiedTime();
dcheng 2017/04/12 00:56:09 Ditto: omit Clipboard in the names here.
Mark P 2017/04/12 21:33:51 Done.
54 bool HasFormat(const std::string& format); 62 bool HasFormat(const std::string& format);
63 void OnPrimaryClipboardChanged();
55 void Set(const std::string& format, const std::string& data); 64 void Set(const std::string& format, const std::string& data);
56 void CommitToAndroidClipboard(); 65 void CommitToAndroidClipboard();
57 void Clear(); 66 void Clear();
58 67
59 private: 68 private:
60 void UpdateFromAndroidClipboard(); 69 void UpdateFromAndroidClipboard();
70 void UpdateLastModifiedTimePref();
61 std::map<std::string, std::string> map_; 71 std::map<std::string, std::string> map_;
62 base::Lock lock_; 72 base::Lock lock_;
63 73
64 int64_t last_clipboard_change_time_ms_; 74 uint64_t sequence_number_;
75 base::Time clipboard_last_modified_time_;
dcheng 2017/04/12 00:56:09 Nit: no clipboard_
Mark P 2017/04/12 21:33:51 Done.
65 76
66 // Java class and methods for the Android ClipboardManager. 77 // Java class and methods for the Android ClipboardManager.
67 ScopedJavaGlobalRef<jobject> clipboard_manager_; 78 ScopedJavaGlobalRef<jobject> clipboard_manager_;
68 }; 79 };
69 base::LazyInstance<ClipboardMap>::Leaky g_map = LAZY_INSTANCE_INITIALIZER; 80 base::LazyInstance<ClipboardMap>::Leaky g_map = LAZY_INSTANCE_INITIALIZER;
70 81
71 ClipboardMap::ClipboardMap() { 82 ClipboardMap::ClipboardMap() {
72 clipboard_manager_.Reset(Java_Clipboard_getInstance(AttachCurrentThread())); 83 clipboard_manager_.Reset(Java_Clipboard_getInstance(AttachCurrentThread()));
73 DCHECK(clipboard_manager_.obj()); 84 DCHECK(clipboard_manager_.obj());
85 UpdateFromAndroidClipboard();
86 // ***
87 // Read |clipboard_last_modified_time_| as a time (in seconds) from prefs
88 // under name |kClipboardLastModifiedTimePref|. Use 0 if the pref doesn't
89 // exist.
74 } 90 }
75 91
76 std::string ClipboardMap::Get(const std::string& format) { 92 std::string ClipboardMap::Get(const std::string& format) {
77 base::AutoLock lock(lock_); 93 base::AutoLock lock(lock_);
78 UpdateFromAndroidClipboard();
79 std::map<std::string, std::string>::const_iterator it = map_.find(format); 94 std::map<std::string, std::string>::const_iterator it = map_.find(format);
80 return it == map_.end() ? std::string() : it->second; 95 return it == map_.end() ? std::string() : it->second;
81 } 96 }
82 97
83 int64_t ClipboardMap::GetLastClipboardChangeTimeInMillis() { 98 uint64_t ClipboardMap::GetSequenceNumber() const {
84 base::AutoLock lock(lock_); 99 return sequence_number_;
85 UpdateFromAndroidClipboard(); 100 }
86 return last_clipboard_change_time_ms_; 101
102 base::Time ClipboardMap::GetClipboardLastModifiedTime() const {
103 return clipboard_last_modified_time_;
104 }
105
106 void ClipboardMap::ClearClipboardLastModifiedTime() {
107 clipboard_last_modified_time_ = base::Time();
108 UpdateLastModifiedTimePref();
87 } 109 }
88 110
89 bool ClipboardMap::HasFormat(const std::string& format) { 111 bool ClipboardMap::HasFormat(const std::string& format) {
90 base::AutoLock lock(lock_); 112 base::AutoLock lock(lock_);
113 return base::ContainsKey(map_, format);
114 }
115
116 void ClipboardMap::OnPrimaryClipboardChanged() {
117 sequence_number_++;
118 clipboard_last_modified_time_ = base::Time::Now();
119 UpdateLastModifiedTimePref();
91 UpdateFromAndroidClipboard(); 120 UpdateFromAndroidClipboard();
dcheng 2017/04/12 00:56:09 I do wonder if we want to do this work up-front wh
Mark P 2017/04/12 04:21:11 Sure, I think I can do that pretty cleanly. I'll m
Mark P 2017/04/12 21:33:51 Done.
92 return base::ContainsKey(map_, format);
93 } 121 }
94 122
95 void ClipboardMap::Set(const std::string& format, const std::string& data) { 123 void ClipboardMap::Set(const std::string& format, const std::string& data) {
96 base::AutoLock lock(lock_); 124 base::AutoLock lock(lock_);
97 map_[format] = data; 125 map_[format] = data;
98 } 126 }
99 127
100 void ClipboardMap::CommitToAndroidClipboard() { 128 void ClipboardMap::CommitToAndroidClipboard() {
101 JNIEnv* env = AttachCurrentThread(); 129 JNIEnv* env = AttachCurrentThread();
102 base::AutoLock lock(lock_); 130 base::AutoLock lock(lock_);
(...skipping 12 matching lines...) Expand all
115 Java_Clipboard_setHTMLText(env, clipboard_manager_, html, text); 143 Java_Clipboard_setHTMLText(env, clipboard_manager_, html, text);
116 } else if (base::ContainsKey(map_, kPlainTextFormat)) { 144 } else if (base::ContainsKey(map_, kPlainTextFormat)) {
117 ScopedJavaLocalRef<jstring> str = 145 ScopedJavaLocalRef<jstring> str =
118 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]); 146 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]);
119 DCHECK(str.obj()); 147 DCHECK(str.obj());
120 Java_Clipboard_setText(env, clipboard_manager_, str); 148 Java_Clipboard_setText(env, clipboard_manager_, str);
121 } else { 149 } else {
122 Java_Clipboard_clear(env, clipboard_manager_); 150 Java_Clipboard_clear(env, clipboard_manager_);
123 NOTIMPLEMENTED(); 151 NOTIMPLEMENTED();
124 } 152 }
153 sequence_number_++;
154 clipboard_last_modified_time_ = base::Time::Now();
155 UpdateLastModifiedTimePref();
125 } 156 }
126 157
127 void ClipboardMap::Clear() { 158 void ClipboardMap::Clear() {
128 JNIEnv* env = AttachCurrentThread(); 159 JNIEnv* env = AttachCurrentThread();
129 base::AutoLock lock(lock_); 160 base::AutoLock lock(lock_);
130 map_.clear(); 161 map_.clear();
131 Java_Clipboard_clear(env, clipboard_manager_); 162 Java_Clipboard_clear(env, clipboard_manager_);
163 sequence_number_++;
164 clipboard_last_modified_time_ = base::Time::Now();
165 UpdateLastModifiedTimePref();
132 } 166 }
133 167
134 // Add a key:jstr pair to map, but only if jstr is not null, and also 168 // Add a key:jstr pair to map, but only if jstr is not null, and also
135 // not empty. 169 // not empty.
136 void AddMapEntry(JNIEnv* env, 170 void AddMapEntry(JNIEnv* env,
137 std::map<std::string, std::string>* map, 171 std::map<std::string, std::string>* map,
138 const char* key, 172 const char* key,
139 const ScopedJavaLocalRef<jstring>& jstr) { 173 const ScopedJavaLocalRef<jstring>& jstr) {
140 if (!jstr.is_null()) { 174 if (!jstr.is_null()) {
141 std::string str = ConvertJavaStringToUTF8(env, jstr.obj()); 175 std::string str = ConvertJavaStringToUTF8(env, jstr.obj());
142 if (!str.empty()) 176 if (!str.empty())
143 (*map)[key] = str; 177 (*map)[key] = str;
144 } 178 }
145 } 179 }
146 180
147 // Return true if all the key-value pairs in map1 are also in map2.
148 bool MapIsSubset(const std::map<std::string, std::string>& map1,
149 const std::map<std::string, std::string>& map2) {
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
158 void ClipboardMap::UpdateFromAndroidClipboard() { 181 void ClipboardMap::UpdateFromAndroidClipboard() {
159 // Fetch the current Android clipboard state. Replace our state with 182 // Fetch the current Android clipboard state.
160 // the Android state if the Android state has been changed.
161 lock_.AssertAcquired(); 183 lock_.AssertAcquired();
162 JNIEnv* env = AttachCurrentThread(); 184 JNIEnv* env = AttachCurrentThread();
163 185
164 std::map<std::string, std::string> android_clipboard_state;
165
166 ScopedJavaLocalRef<jstring> jtext = 186 ScopedJavaLocalRef<jstring> jtext =
167 Java_Clipboard_getCoercedText(env, clipboard_manager_); 187 Java_Clipboard_getCoercedText(env, clipboard_manager_);
168 ScopedJavaLocalRef<jstring> jhtml = 188 ScopedJavaLocalRef<jstring> jhtml =
169 Java_Clipboard_getHTMLText(env, clipboard_manager_); 189 Java_Clipboard_getHTMLText(env, clipboard_manager_);
170 190
171 AddMapEntry(env, &android_clipboard_state, kPlainTextFormat, jtext); 191 AddMapEntry(env, &map_, kPlainTextFormat, jtext);
172 AddMapEntry(env, &android_clipboard_state, kHTMLFormat, jhtml); 192 AddMapEntry(env, &map_, kHTMLFormat, jhtml);
173 last_clipboard_change_time_ms_ = 193 }
174 Java_Clipboard_getClipboardContentChangeTimeInMillis(env,
175 clipboard_manager_);
176 194
177 if (!MapIsSubset(android_clipboard_state, map_)) 195 void ClipboardMap::UpdateLastModifiedTimePref() {
178 android_clipboard_state.swap(map_); 196 // ***
197 // Record |clipboard_last_modified_time_| as a time (in seconds) to prefs
198 // under name |kClipboardLastModifiedTimePref|. Make sure that null times
199 // get recorded as 0.
179 } 200 }
180 201
181 } // namespace 202 } // namespace
182 203
183 // Clipboard::FormatType implementation. 204 // Clipboard::FormatType implementation.
184 Clipboard::FormatType::FormatType() { 205 Clipboard::FormatType::FormatType() {
185 } 206 }
186 207
187 Clipboard::FormatType::FormatType(const std::string& native_format) 208 Clipboard::FormatType::FormatType(const std::string& native_format)
188 : data_(native_format) { 209 : data_(native_format) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 return type; 291 return type;
271 } 292 }
272 293
273 // Clipboard factory method. 294 // Clipboard factory method.
274 // static 295 // static
275 Clipboard* Clipboard::Create() { 296 Clipboard* Clipboard::Create() {
276 return new ClipboardAndroid; 297 return new ClipboardAndroid;
277 } 298 }
278 299
279 // ClipboardAndroid implementation. 300 // ClipboardAndroid implementation.
301
302 // static
303 void ClipboardAndroid::RegisterPrefs(PrefRegistrySimple* registry) {
304 registry->RegisterUint64Pref(kClipboardLastModifiedTimePref, 0u);
305 }
306
307 void ClipboardAndroid::OnPrimaryClipChanged(
308 JNIEnv* env,
309 const base::android::JavaParamRef<jobject>& obj) {
310 g_map.Get().OnPrimaryClipboardChanged();
311 }
312
280 ClipboardAndroid::ClipboardAndroid() { 313 ClipboardAndroid::ClipboardAndroid() {
281 DCHECK(CalledOnValidThread()); 314 DCHECK(CalledOnValidThread());
282 } 315 }
283 316
284 ClipboardAndroid::~ClipboardAndroid() { 317 ClipboardAndroid::~ClipboardAndroid() {
285 DCHECK(CalledOnValidThread()); 318 DCHECK(CalledOnValidThread());
286 } 319 }
287 320
288 void ClipboardAndroid::OnPreShutdown() {} 321 void ClipboardAndroid::OnPreShutdown() {}
289 322
290 uint64_t ClipboardAndroid::GetSequenceNumber(ClipboardType /* type */) const { 323 uint64_t ClipboardAndroid::GetSequenceNumber(ClipboardType /* type */) const {
291 DCHECK(CalledOnValidThread()); 324 DCHECK(CalledOnValidThread());
292 // TODO: implement this. For now this interface will advertise 325 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 } 326 }
297 327
298 bool ClipboardAndroid::IsFormatAvailable(const Clipboard::FormatType& format, 328 bool ClipboardAndroid::IsFormatAvailable(const Clipboard::FormatType& format,
299 ClipboardType type) const { 329 ClipboardType type) const {
300 DCHECK(CalledOnValidThread()); 330 DCHECK(CalledOnValidThread());
301 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 331 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
302 return g_map.Get().HasFormat(format.ToString()); 332 return g_map.Get().HasFormat(format.ToString());
303 } 333 }
304 334
305 void ClipboardAndroid::Clear(ClipboardType type) { 335 void ClipboardAndroid::Clear(ClipboardType type) {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 } 439 }
410 440
411 void ClipboardAndroid::ReadData(const Clipboard::FormatType& format, 441 void ClipboardAndroid::ReadData(const Clipboard::FormatType& format,
412 std::string* result) const { 442 std::string* result) const {
413 DCHECK(CalledOnValidThread()); 443 DCHECK(CalledOnValidThread());
414 *result = g_map.Get().Get(format.ToString()); 444 *result = g_map.Get().Get(format.ToString());
415 } 445 }
416 446
417 base::Time ClipboardAndroid::GetClipboardLastModifiedTime() const { 447 base::Time ClipboardAndroid::GetClipboardLastModifiedTime() const {
418 DCHECK(CalledOnValidThread()); 448 DCHECK(CalledOnValidThread());
419 return base::Time::FromJavaTime( 449 return g_map.Get().GetClipboardLastModifiedTime();
420 g_map.Get().GetLastClipboardChangeTimeInMillis()); 450 }
451
452 void ClipboardAndroid::ClearClipboardLastModifiedTime() {
453 DCHECK(CalledOnValidThread());
454 g_map.Get().ClearClipboardLastModifiedTime();
421 } 455 }
422 456
423 // Main entry point used to write several values in the clipboard. 457 // Main entry point used to write several values in the clipboard.
424 void ClipboardAndroid::WriteObjects(ClipboardType type, 458 void ClipboardAndroid::WriteObjects(ClipboardType type,
425 const ObjectMap& objects) { 459 const ObjectMap& objects) {
426 DCHECK(CalledOnValidThread()); 460 DCHECK(CalledOnValidThread());
427 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE); 461 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
428 g_map.Get().Clear(); 462 g_map.Get().Clear();
429 463
430 for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end(); 464 for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 } 512 }
479 g_map.Get().Set(kBitmapFormat, packed); 513 g_map.Get().Set(kBitmapFormat, packed);
480 } 514 }
481 515
482 void ClipboardAndroid::WriteData(const Clipboard::FormatType& format, 516 void ClipboardAndroid::WriteData(const Clipboard::FormatType& format,
483 const char* data_data, 517 const char* data_data,
484 size_t data_len) { 518 size_t data_len) {
485 g_map.Get().Set(format.ToString(), std::string(data_data, data_len)); 519 g_map.Get().Set(format.ToString(), std::string(data_data, data_len));
486 } 520 }
487 521
522 bool RegisterClipboardAndroid(JNIEnv* env) {
523 return RegisterNativesImpl(env);
524 }
525
526 // Returns a pointer to the current ClipboardAndroid object.
527 static jlong Init(JNIEnv* env,
528 const base::android::JavaParamRef<jobject>& obj) {
529 return reinterpret_cast<intptr_t>(Clipboard::GetForCurrentThread());
530 }
531
488 } // namespace ui 532 } // namespace ui
OLDNEW
« ui/base/clipboard/clipboard.h ('K') | « ui/base/clipboard/clipboard_android.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698