Chromium Code Reviews| 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 | |
|
Bernhard Bauer
2017/04/25 13:30:06
base::Time?
Mark P
2017/04/25 18:51:21
Correct. Done.
| |
| 46 // a pref in local store. (I.e., this is not a per-profile pref.) | |
|
Bernhard Bauer
2017/04/25 13:30:06
Again, also kind of a layering violation, but I gu
Mark P
2017/04/25 18:51:21
Acknowledged.
| |
| 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 // Updates |last_modified_time_| to |time| and writes it to |local_state_|. | |
| 80 void UpdateLastModifiedTime(const base::Time& time); | |
| 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 UpdateLastModifiedTime(base::Time()); |
| 107 } | 127 } |
| 108 | 128 |
| 109 bool ClipboardMap::HasFormat(const std::string& format) { | 129 bool ClipboardMap::HasFormat(const std::string& format) { |
| 110 base::AutoLock lock(lock_); | 130 base::AutoLock lock(lock_); |
| 111 UpdateFromAndroidClipboard(); | 131 UpdateFromAndroidClipboard(); |
| 112 return base::ContainsKey(map_, format); | 132 return base::ContainsKey(map_, format); |
| 113 } | 133 } |
| 114 | 134 |
| 115 void ClipboardMap::OnPrimaryClipboardChanged() { | 135 void ClipboardMap::OnPrimaryClipboardChanged() { |
| 116 sequence_number_++; | 136 sequence_number_++; |
| 117 last_modified_time_ = base::Time::Now(); | 137 UpdateLastModifiedTime(base::Time::Now()); |
| 118 map_state_ = MapState::kOutOfDate; | 138 map_state_ = MapState::kOutOfDate; |
| 119 } | 139 } |
| 120 | 140 |
| 121 void ClipboardMap::Set(const std::string& format, const std::string& data) { | 141 void ClipboardMap::Set(const std::string& format, const std::string& data) { |
| 122 base::AutoLock lock(lock_); | 142 base::AutoLock lock(lock_); |
| 123 map_[format] = data; | 143 map_[format] = data; |
| 124 map_state_ = MapState::kPreparingCommit; | 144 map_state_ = MapState::kPreparingCommit; |
| 125 } | 145 } |
| 126 | 146 |
| 127 void ClipboardMap::CommitToAndroidClipboard() { | 147 void ClipboardMap::CommitToAndroidClipboard() { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 144 ScopedJavaLocalRef<jstring> str = | 164 ScopedJavaLocalRef<jstring> str = |
| 145 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]); | 165 ConvertUTF8ToJavaString(env, map_[kPlainTextFormat]); |
| 146 DCHECK(str.obj()); | 166 DCHECK(str.obj()); |
| 147 Java_Clipboard_setText(env, clipboard_manager_, str); | 167 Java_Clipboard_setText(env, clipboard_manager_, str); |
| 148 } else { | 168 } else { |
| 149 Java_Clipboard_clear(env, clipboard_manager_); | 169 Java_Clipboard_clear(env, clipboard_manager_); |
| 150 NOTIMPLEMENTED(); | 170 NOTIMPLEMENTED(); |
| 151 } | 171 } |
| 152 map_state_ = MapState::kUpToDate; | 172 map_state_ = MapState::kUpToDate; |
| 153 sequence_number_++; | 173 sequence_number_++; |
| 154 last_modified_time_ = base::Time::Now(); | 174 UpdateLastModifiedTime(base::Time::Now()); |
| 155 } | 175 } |
| 156 | 176 |
| 157 void ClipboardMap::Clear() { | 177 void ClipboardMap::Clear() { |
| 158 JNIEnv* env = AttachCurrentThread(); | 178 JNIEnv* env = AttachCurrentThread(); |
| 159 base::AutoLock lock(lock_); | 179 base::AutoLock lock(lock_); |
| 160 map_.clear(); | 180 map_.clear(); |
| 161 Java_Clipboard_clear(env, clipboard_manager_); | 181 Java_Clipboard_clear(env, clipboard_manager_); |
| 162 map_state_ = MapState::kUpToDate; | 182 map_state_ = MapState::kUpToDate; |
| 163 sequence_number_++; | 183 sequence_number_++; |
| 164 last_modified_time_ = base::Time::Now(); | 184 UpdateLastModifiedTime(base::Time::Now()); |
| 165 } | 185 } |
| 166 | 186 |
| 167 // Add a key:jstr pair to map, but only if jstr is not null, and also | 187 // Add a key:jstr pair to map, but only if jstr is not null, and also |
| 168 // not empty. | 188 // not empty. |
| 169 void AddMapEntry(JNIEnv* env, | 189 void AddMapEntry(JNIEnv* env, |
| 170 std::map<std::string, std::string>* map, | 190 std::map<std::string, std::string>* map, |
| 171 const char* key, | 191 const char* key, |
| 172 const ScopedJavaLocalRef<jstring>& jstr) { | 192 const ScopedJavaLocalRef<jstring>& jstr) { |
| 173 if (!jstr.is_null()) { | 193 if (!jstr.is_null()) { |
| 174 std::string str = ConvertJavaStringToUTF8(env, jstr.obj()); | 194 std::string str = ConvertJavaStringToUTF8(env, jstr.obj()); |
| 175 if (!str.empty()) | 195 if (!str.empty()) |
| 176 (*map)[key] = str; | 196 (*map)[key] = str; |
| 177 } | 197 } |
| 178 } | 198 } |
| 179 | 199 |
| 200 void ClipboardMap::UpdateLastModifiedTime(const base::Time& time) { | |
|
dcheng
2017/04/25 13:17:12
base::Time is designed to be efficiently passed by
Mark P
2017/04/25 18:51:21
Done.
| |
| 201 last_modified_time_ = time; | |
| 202 // |local_state_| may be null in tests. | |
| 203 if (local_state_) { | |
| 204 local_state_->SetInt64(kClipboardLastModifiedTimePref, | |
| 205 last_modified_time_.ToInternalValue()); | |
| 206 } | |
| 207 } | |
| 208 | |
| 180 void ClipboardMap::UpdateFromAndroidClipboard() { | 209 void ClipboardMap::UpdateFromAndroidClipboard() { |
| 181 DCHECK_NE(MapState::kPreparingCommit, map_state_); | 210 DCHECK_NE(MapState::kPreparingCommit, map_state_); |
| 182 if (map_state_ == MapState::kUpToDate) | 211 if (map_state_ == MapState::kUpToDate) |
| 183 return; | 212 return; |
| 184 | 213 |
| 185 // Fetch the current Android clipboard state. | 214 // Fetch the current Android clipboard state. |
| 186 lock_.AssertAcquired(); | 215 lock_.AssertAcquired(); |
| 187 JNIEnv* env = AttachCurrentThread(); | 216 JNIEnv* env = AttachCurrentThread(); |
| 188 | 217 |
| 189 ScopedJavaLocalRef<jstring> jtext = | 218 ScopedJavaLocalRef<jstring> jtext = |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 } | 319 } |
| 291 | 320 |
| 292 // Clipboard factory method. | 321 // Clipboard factory method. |
| 293 // static | 322 // static |
| 294 Clipboard* Clipboard::Create() { | 323 Clipboard* Clipboard::Create() { |
| 295 return new ClipboardAndroid; | 324 return new ClipboardAndroid; |
| 296 } | 325 } |
| 297 | 326 |
| 298 // ClipboardAndroid implementation. | 327 // ClipboardAndroid implementation. |
| 299 | 328 |
| 329 // static | |
| 330 void ClipboardAndroid::RegisterPrefs(PrefRegistrySimple* registry) { | |
| 331 registry->RegisterInt64Pref(kClipboardLastModifiedTimePref, 0u); | |
| 332 } | |
| 333 | |
| 334 void ClipboardAndroid::SetLocalState(PrefService* local_state) { | |
| 335 g_map.Get().SetLocalState(local_state); | |
| 336 } | |
| 337 | |
| 300 void ClipboardAndroid::OnPrimaryClipChanged( | 338 void ClipboardAndroid::OnPrimaryClipChanged( |
| 301 JNIEnv* env, | 339 JNIEnv* env, |
| 302 const base::android::JavaParamRef<jobject>& obj) { | 340 const base::android::JavaParamRef<jobject>& obj) { |
| 303 g_map.Get().OnPrimaryClipboardChanged(); | 341 g_map.Get().OnPrimaryClipboardChanged(); |
| 304 } | 342 } |
| 305 | 343 |
| 306 ClipboardAndroid::ClipboardAndroid() { | 344 ClipboardAndroid::ClipboardAndroid() { |
| 307 DCHECK(CalledOnValidThread()); | 345 DCHECK(CalledOnValidThread()); |
| 308 } | 346 } |
| 309 | 347 |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 513 return RegisterNativesImpl(env); | 551 return RegisterNativesImpl(env); |
| 514 } | 552 } |
| 515 | 553 |
| 516 // Returns a pointer to the current ClipboardAndroid object. | 554 // Returns a pointer to the current ClipboardAndroid object. |
| 517 static jlong Init(JNIEnv* env, | 555 static jlong Init(JNIEnv* env, |
| 518 const base::android::JavaParamRef<jobject>& obj) { | 556 const base::android::JavaParamRef<jobject>& obj) { |
| 519 return reinterpret_cast<intptr_t>(Clipboard::GetForCurrentThread()); | 557 return reinterpret_cast<intptr_t>(Clipboard::GetForCurrentThread()); |
| 520 } | 558 } |
| 521 | 559 |
| 522 } // namespace ui | 560 } // namespace ui |
| OLD | NEW |