OLD | NEW |
---|---|
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/android/scoped_java_ref.h" |
12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
15 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
16 #include "base/time/time.h" | 16 #include "base/time/time.h" |
17 #include "components/prefs/pref_registry_simple.h" | |
18 #include "components/prefs/pref_service.h" | |
17 #include "jni/Clipboard_jni.h" | 19 #include "jni/Clipboard_jni.h" |
18 #include "third_party/skia/include/core/SkBitmap.h" | 20 #include "third_party/skia/include/core/SkBitmap.h" |
19 #include "ui/gfx/geometry/size.h" | 21 #include "ui/gfx/geometry/size.h" |
20 | 22 |
21 // TODO:(andrewhayden) Support additional formats in Android: Bitmap, URI, HTML, | 23 // TODO:(andrewhayden) Support additional formats in Android: Bitmap, URI, HTML, |
22 // HTML+text now that Android's clipboard system supports them, then nuke the | 24 // HTML+text now that Android's clipboard system supports them, then nuke the |
23 // legacy implementation note below. | 25 // legacy implementation note below. |
24 | 26 |
25 // Legacy implementation note: | 27 // Legacy implementation note: |
26 // The Android clipboard system used to only support text format. So we used the | 28 // The Android clipboard system used to only support text format. So we used the |
27 // Android system when some text was added or retrieved from the system. For | 29 // Android system when some text was added or retrieved from the system. For |
28 // anything else, we STILL store the value in some process wide static | 30 // anything else, we STILL store the value in some process wide static |
29 // variable protected by a lock. So the (non-text) clipboard will only work | 31 // variable protected by a lock. So the (non-text) clipboard will only work |
30 // within the same process. | 32 // within the same process. |
31 | 33 |
32 using base::android::AttachCurrentThread; | 34 using base::android::AttachCurrentThread; |
33 using base::android::ClearException; | 35 using base::android::ClearException; |
34 using base::android::ConvertJavaStringToUTF8; | 36 using base::android::ConvertJavaStringToUTF8; |
35 using base::android::ConvertUTF8ToJavaString; | 37 using base::android::ConvertUTF8ToJavaString; |
36 using base::android::ScopedJavaGlobalRef; | 38 using base::android::ScopedJavaGlobalRef; |
37 using base::android::ScopedJavaLocalRef; | 39 using base::android::ScopedJavaLocalRef; |
38 | 40 |
39 namespace ui { | 41 namespace ui { |
40 | 42 |
41 namespace { | 43 namespace { |
42 | 44 |
45 // Stores the last modified time in Time::Time's internal format (int64) as | |
46 // a pref in local store. (I.e., this is not a per-profile pref.) | |
47 const char kClipboardLastModifiedTimePref[] = "ui.clipboard.last_modified_time"; | |
48 | |
43 // Various formats we support. | 49 // Various formats we support. |
44 const char kURLFormat[] = "url"; | 50 const char kURLFormat[] = "url"; |
45 const char kPlainTextFormat[] = "text"; | 51 const char kPlainTextFormat[] = "text"; |
46 const char kHTMLFormat[] = "html"; | 52 const char kHTMLFormat[] = "html"; |
47 const char kRTFFormat[] = "rtf"; | 53 const char kRTFFormat[] = "rtf"; |
48 const char kBitmapFormat[] = "bitmap"; | 54 const char kBitmapFormat[] = "bitmap"; |
49 const char kWebKitSmartPasteFormat[] = "webkit_smart"; | 55 const char kWebKitSmartPasteFormat[] = "webkit_smart"; |
50 const char kBookmarkFormat[] = "bookmark"; | 56 const char kBookmarkFormat[] = "bookmark"; |
51 | 57 |
52 class ClipboardMap { | 58 class ClipboardMap { |
53 public: | 59 public: |
54 ClipboardMap(); | 60 ClipboardMap(); |
61 void SetLocalState(PrefService* local_state); | |
55 std::string Get(const std::string& format); | 62 std::string Get(const std::string& format); |
56 uint64_t GetSequenceNumber() const; | 63 uint64_t GetSequenceNumber() const; |
57 base::Time GetLastModifiedTime() const; | 64 base::Time GetLastModifiedTime() const; |
58 void ClearLastModifiedTime(); | 65 void ClearLastModifiedTime(); |
59 bool HasFormat(const std::string& format); | 66 bool HasFormat(const std::string& format); |
60 void OnPrimaryClipboardChanged(); | 67 void OnPrimaryClipboardChanged(); |
61 void Set(const std::string& format, const std::string& data); | 68 void Set(const std::string& format, const std::string& data); |
62 void CommitToAndroidClipboard(); | 69 void CommitToAndroidClipboard(); |
63 void Clear(); | 70 void Clear(); |
64 | 71 |
65 private: | 72 private: |
66 enum class MapState { | 73 enum class MapState { |
67 kOutOfDate, | 74 kOutOfDate, |
68 kUpToDate, | 75 kUpToDate, |
69 kPreparingCommit, | 76 kPreparingCommit, |
70 }; | 77 }; |
71 | 78 |
79 // Writes |last_modified_time_| to |local_state_|. | |
80 void UpdateLastModifiedTimePref(); | |
81 | |
82 // Updates |map_| and |map_state_| if necessary by fetching data from Java. | |
72 void UpdateFromAndroidClipboard(); | 83 void UpdateFromAndroidClipboard(); |
84 | |
73 std::map<std::string, std::string> map_; | 85 std::map<std::string, std::string> map_; |
74 MapState map_state_; | 86 MapState map_state_; |
75 base::Lock lock_; | 87 base::Lock lock_; |
76 | 88 |
77 uint64_t sequence_number_; | 89 uint64_t sequence_number_; |
78 base::Time last_modified_time_; | 90 base::Time last_modified_time_; |
79 | 91 |
92 PrefService* local_state_; | |
93 | |
80 // Java class and methods for the Android ClipboardManager. | 94 // Java class and methods for the Android ClipboardManager. |
81 ScopedJavaGlobalRef<jobject> clipboard_manager_; | 95 ScopedJavaGlobalRef<jobject> clipboard_manager_; |
82 }; | 96 }; |
83 base::LazyInstance<ClipboardMap>::Leaky g_map = LAZY_INSTANCE_INITIALIZER; | 97 base::LazyInstance<ClipboardMap>::Leaky g_map = LAZY_INSTANCE_INITIALIZER; |
84 | 98 |
85 ClipboardMap::ClipboardMap() : map_state_(MapState::kOutOfDate) { | 99 ClipboardMap::ClipboardMap() : map_state_(MapState::kOutOfDate) { |
86 clipboard_manager_.Reset(Java_Clipboard_getInstance(AttachCurrentThread())); | 100 clipboard_manager_.Reset(Java_Clipboard_getInstance(AttachCurrentThread())); |
87 DCHECK(clipboard_manager_.obj()); | 101 DCHECK(clipboard_manager_.obj()); |
88 } | 102 } |
89 | 103 |
104 void ClipboardMap::SetLocalState(PrefService* local_state) { | |
105 local_state_ = local_state; | |
106 last_modified_time_ = base::Time::FromInternalValue( | |
107 local_state_->GetInt64(kClipboardLastModifiedTimePref)); | |
108 } | |
109 | |
90 std::string ClipboardMap::Get(const std::string& format) { | 110 std::string ClipboardMap::Get(const std::string& format) { |
91 base::AutoLock lock(lock_); | 111 base::AutoLock lock(lock_); |
92 UpdateFromAndroidClipboard(); | 112 UpdateFromAndroidClipboard(); |
93 std::map<std::string, std::string>::const_iterator it = map_.find(format); | 113 std::map<std::string, std::string>::const_iterator it = map_.find(format); |
94 return it == map_.end() ? std::string() : it->second; | 114 return it == map_.end() ? std::string() : it->second; |
95 } | 115 } |
96 | 116 |
97 uint64_t ClipboardMap::GetSequenceNumber() const { | 117 uint64_t ClipboardMap::GetSequenceNumber() const { |
98 return sequence_number_; | 118 return sequence_number_; |
99 } | 119 } |
100 | 120 |
101 base::Time ClipboardMap::GetLastModifiedTime() const { | 121 base::Time ClipboardMap::GetLastModifiedTime() const { |
102 return last_modified_time_; | 122 return last_modified_time_; |
103 } | 123 } |
104 | 124 |
105 void ClipboardMap::ClearLastModifiedTime() { | 125 void ClipboardMap::ClearLastModifiedTime() { |
106 last_modified_time_ = base::Time(); | 126 last_modified_time_ = base::Time(); |
127 UpdateLastModifiedTimePref(); | |
107 } | 128 } |
108 | 129 |
109 bool ClipboardMap::HasFormat(const std::string& format) { | 130 bool ClipboardMap::HasFormat(const std::string& format) { |
110 base::AutoLock lock(lock_); | 131 base::AutoLock lock(lock_); |
111 UpdateFromAndroidClipboard(); | 132 UpdateFromAndroidClipboard(); |
112 return base::ContainsKey(map_, format); | 133 return base::ContainsKey(map_, format); |
113 } | 134 } |
114 | 135 |
115 void ClipboardMap::OnPrimaryClipboardChanged() { | 136 void ClipboardMap::OnPrimaryClipboardChanged() { |
116 sequence_number_++; | 137 sequence_number_++; |
117 last_modified_time_ = base::Time::Now(); | 138 last_modified_time_ = base::Time::Now(); |
139 UpdateLastModifiedTimePref(); | |
118 map_state_ = MapState::kOutOfDate; | 140 map_state_ = MapState::kOutOfDate; |
119 } | 141 } |
120 | 142 |
121 void ClipboardMap::Set(const std::string& format, const std::string& data) { | 143 void ClipboardMap::Set(const std::string& format, const std::string& data) { |
122 base::AutoLock lock(lock_); | 144 base::AutoLock lock(lock_); |
123 map_[format] = data; | 145 map_[format] = data; |
124 map_state_ = MapState::kPreparingCommit; | 146 map_state_ = MapState::kPreparingCommit; |
125 } | 147 } |
126 | 148 |
127 void ClipboardMap::CommitToAndroidClipboard() { | 149 void ClipboardMap::CommitToAndroidClipboard() { |
(...skipping 17 matching lines...) Expand all Loading... | |
145 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]); | 167 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]); |
146 DCHECK(str.obj()); | 168 DCHECK(str.obj()); |
147 Java_Clipboard_setText(env, clipboard_manager_, str); | 169 Java_Clipboard_setText(env, clipboard_manager_, str); |
148 } else { | 170 } else { |
149 Java_Clipboard_clear(env, clipboard_manager_); | 171 Java_Clipboard_clear(env, clipboard_manager_); |
150 NOTIMPLEMENTED(); | 172 NOTIMPLEMENTED(); |
151 } | 173 } |
152 map_state_ = MapState::kUpToDate; | 174 map_state_ = MapState::kUpToDate; |
153 sequence_number_++; | 175 sequence_number_++; |
154 last_modified_time_ = base::Time::Now(); | 176 last_modified_time_ = base::Time::Now(); |
177 UpdateLastModifiedTimePref(); | |
155 } | 178 } |
156 | 179 |
157 void ClipboardMap::Clear() { | 180 void ClipboardMap::Clear() { |
158 JNIEnv* env = AttachCurrentThread(); | 181 JNIEnv* env = AttachCurrentThread(); |
159 base::AutoLock lock(lock_); | 182 base::AutoLock lock(lock_); |
160 map_.clear(); | 183 map_.clear(); |
161 Java_Clipboard_clear(env, clipboard_manager_); | 184 Java_Clipboard_clear(env, clipboard_manager_); |
162 map_state_ = MapState::kUpToDate; | 185 map_state_ = MapState::kUpToDate; |
163 sequence_number_++; | 186 sequence_number_++; |
164 last_modified_time_ = base::Time::Now(); | 187 last_modified_time_ = base::Time::Now(); |
188 UpdateLastModifiedTimePref(); | |
Ted C
2017/04/24 20:45:48
should we make UpdateLastModifiedTimePref take the
Mark P
2017/04/24 22:19:56
Makes sense to me. Done.
| |
165 } | 189 } |
166 | 190 |
167 // Add a key:jstr pair to map, but only if jstr is not null, and also | 191 // Add a key:jstr pair to map, but only if jstr is not null, and also |
168 // not empty. | 192 // not empty. |
169 void AddMapEntry(JNIEnv* env, | 193 void AddMapEntry(JNIEnv* env, |
170 std::map<std::string, std::string>* map, | 194 std::map<std::string, std::string>* map, |
171 const char* key, | 195 const char* key, |
172 const ScopedJavaLocalRef<jstring>& jstr) { | 196 const ScopedJavaLocalRef<jstring>& jstr) { |
173 if (!jstr.is_null()) { | 197 if (!jstr.is_null()) { |
174 std::string str = ConvertJavaStringToUTF8(env, jstr.obj()); | 198 std::string str = ConvertJavaStringToUTF8(env, jstr.obj()); |
175 if (!str.empty()) | 199 if (!str.empty()) |
176 (*map)[key] = str; | 200 (*map)[key] = str; |
177 } | 201 } |
178 } | 202 } |
179 | 203 |
204 void ClipboardMap::UpdateLastModifiedTimePref() { | |
205 // |local_state_| may be null in tests. | |
206 if (local_state_) { | |
207 local_state_->SetInt64(kClipboardLastModifiedTimePref, | |
208 last_modified_time_.ToInternalValue()); | |
209 } | |
210 } | |
211 | |
180 void ClipboardMap::UpdateFromAndroidClipboard() { | 212 void ClipboardMap::UpdateFromAndroidClipboard() { |
181 DCHECK_NE(MapState::kPreparingCommit, map_state_); | 213 DCHECK_NE(MapState::kPreparingCommit, map_state_); |
182 if (map_state_ == MapState::kUpToDate) | 214 if (map_state_ == MapState::kUpToDate) |
183 return; | 215 return; |
184 | 216 |
185 // Fetch the current Android clipboard state. | 217 // Fetch the current Android clipboard state. |
186 lock_.AssertAcquired(); | 218 lock_.AssertAcquired(); |
187 JNIEnv* env = AttachCurrentThread(); | 219 JNIEnv* env = AttachCurrentThread(); |
188 | 220 |
189 ScopedJavaLocalRef<jstring> jtext = | 221 ScopedJavaLocalRef<jstring> jtext = |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
290 } | 322 } |
291 | 323 |
292 // Clipboard factory method. | 324 // Clipboard factory method. |
293 // static | 325 // static |
294 Clipboard* Clipboard::Create() { | 326 Clipboard* Clipboard::Create() { |
295 return new ClipboardAndroid; | 327 return new ClipboardAndroid; |
296 } | 328 } |
297 | 329 |
298 // ClipboardAndroid implementation. | 330 // ClipboardAndroid implementation. |
299 | 331 |
332 // static | |
333 void ClipboardAndroid::RegisterPrefs(PrefRegistrySimple* registry) { | |
334 registry->RegisterInt64Pref(kClipboardLastModifiedTimePref, 0u); | |
335 } | |
336 | |
337 void ClipboardAndroid::SetLocalState(PrefService* local_state) { | |
338 g_map.Get().SetLocalState(local_state); | |
339 } | |
340 | |
300 void ClipboardAndroid::OnPrimaryClipChanged( | 341 void ClipboardAndroid::OnPrimaryClipChanged( |
301 JNIEnv* env, | 342 JNIEnv* env, |
302 const base::android::JavaParamRef<jobject>& obj) { | 343 const base::android::JavaParamRef<jobject>& obj) { |
303 g_map.Get().OnPrimaryClipboardChanged(); | 344 g_map.Get().OnPrimaryClipboardChanged(); |
304 } | 345 } |
305 | 346 |
306 ClipboardAndroid::ClipboardAndroid() { | 347 ClipboardAndroid::ClipboardAndroid() { |
307 DCHECK(CalledOnValidThread()); | 348 DCHECK(CalledOnValidThread()); |
308 } | 349 } |
309 | 350 |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
516 return RegisterNativesImpl(env); | 557 return RegisterNativesImpl(env); |
517 } | 558 } |
518 | 559 |
519 // Returns a pointer to the current ClipboardAndroid object. | 560 // Returns a pointer to the current ClipboardAndroid object. |
520 static jlong Init(JNIEnv* env, | 561 static jlong Init(JNIEnv* env, |
521 const base::android::JavaParamRef<jobject>& obj) { | 562 const base::android::JavaParamRef<jobject>& obj) { |
522 return reinterpret_cast<intptr_t>(Clipboard::GetForCurrentThread()); | 563 return reinterpret_cast<intptr_t>(Clipboard::GetForCurrentThread()); |
523 } | 564 } |
524 | 565 |
525 } // namespace ui | 566 } // namespace ui |
OLD | NEW |