Index: ui/base/clipboard/clipboard_android.cc |
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc |
index 8f35282acde0eb701fedebef5ec6aaaad0e84243..1761d6c35e97d96558985cdabaf27963fe43b39b 100644 |
--- a/ui/base/clipboard/clipboard_android.cc |
+++ b/ui/base/clipboard/clipboard_android.cc |
@@ -8,10 +8,12 @@ |
#include "base/android/context_utils.h" |
#include "base/android/jni_string.h" |
+#include "base/android/scoped_java_ref.h" |
#include "base/lazy_instance.h" |
#include "base/stl_util.h" |
#include "base/strings/utf_string_conversions.h" |
#include "base/synchronization/lock.h" |
+#include "base/time/time.h" |
#include "jni/Clipboard_jni.h" |
#include "third_party/skia/include/core/SkBitmap.h" |
#include "ui/gfx/geometry/size.h" |
@@ -37,6 +39,7 @@ using base::android::ScopedJavaLocalRef; |
namespace ui { |
namespace { |
+ |
// Various formats we support. |
const char kURLFormat[] = "url"; |
const char kPlainTextFormat[] = "text"; |
@@ -50,25 +53,36 @@ class ClipboardMap { |
public: |
ClipboardMap(); |
std::string Get(const std::string& format); |
- int64_t GetLastClipboardChangeTimeInMillis(); |
+ uint64_t GetSequenceNumber() const; |
+ base::Time GetLastModifiedTime() const; |
+ void ClearLastModifiedTime(); |
bool HasFormat(const std::string& format); |
+ void OnPrimaryClipboardChanged(); |
void Set(const std::string& format, const std::string& data); |
void CommitToAndroidClipboard(); |
void Clear(); |
private: |
+ enum class MapState { |
+ kOutOfDate, |
+ kUpToDate, |
+ kPreparingCommit, |
+ }; |
+ |
void UpdateFromAndroidClipboard(); |
std::map<std::string, std::string> map_; |
+ MapState map_state_; |
base::Lock lock_; |
- int64_t last_clipboard_change_time_ms_; |
+ uint64_t sequence_number_; |
+ base::Time last_modified_time_; |
// Java class and methods for the Android ClipboardManager. |
ScopedJavaGlobalRef<jobject> clipboard_manager_; |
}; |
base::LazyInstance<ClipboardMap>::Leaky g_map = LAZY_INSTANCE_INITIALIZER; |
-ClipboardMap::ClipboardMap() { |
+ClipboardMap::ClipboardMap() : map_state_(MapState::kOutOfDate) { |
clipboard_manager_.Reset(Java_Clipboard_getInstance(AttachCurrentThread())); |
DCHECK(clipboard_manager_.obj()); |
} |
@@ -80,10 +94,16 @@ std::string ClipboardMap::Get(const std::string& format) { |
return it == map_.end() ? std::string() : it->second; |
} |
-int64_t ClipboardMap::GetLastClipboardChangeTimeInMillis() { |
- base::AutoLock lock(lock_); |
- UpdateFromAndroidClipboard(); |
- return last_clipboard_change_time_ms_; |
+uint64_t ClipboardMap::GetSequenceNumber() const { |
+ return sequence_number_; |
+} |
+ |
+base::Time ClipboardMap::GetLastModifiedTime() const { |
+ return last_modified_time_; |
+} |
+ |
+void ClipboardMap::ClearLastModifiedTime() { |
+ last_modified_time_ = base::Time(); |
} |
bool ClipboardMap::HasFormat(const std::string& format) { |
@@ -92,9 +112,16 @@ bool ClipboardMap::HasFormat(const std::string& format) { |
return base::ContainsKey(map_, format); |
} |
+void ClipboardMap::OnPrimaryClipboardChanged() { |
+ sequence_number_++; |
+ last_modified_time_ = base::Time::Now(); |
+ map_state_ = MapState::kOutOfDate; |
+} |
+ |
void ClipboardMap::Set(const std::string& format, const std::string& data) { |
base::AutoLock lock(lock_); |
map_[format] = data; |
+ map_state_ = MapState::kPreparingCommit; |
} |
void ClipboardMap::CommitToAndroidClipboard() { |
@@ -122,6 +149,9 @@ void ClipboardMap::CommitToAndroidClipboard() { |
Java_Clipboard_clear(env, clipboard_manager_); |
NOTIMPLEMENTED(); |
} |
+ map_state_ = MapState::kUpToDate; |
+ sequence_number_++; |
+ last_modified_time_ = base::Time::Now(); |
} |
void ClipboardMap::Clear() { |
@@ -129,6 +159,9 @@ void ClipboardMap::Clear() { |
base::AutoLock lock(lock_); |
map_.clear(); |
Java_Clipboard_clear(env, clipboard_manager_); |
+ map_state_ = MapState::kUpToDate; |
+ sequence_number_++; |
+ last_modified_time_ = base::Time::Now(); |
} |
// Add a key:jstr pair to map, but only if jstr is not null, and also |
@@ -144,38 +177,24 @@ void AddMapEntry(JNIEnv* env, |
} |
} |
-// Return true if all the key-value pairs in map1 are also in map2. |
-bool MapIsSubset(const std::map<std::string, std::string>& map1, |
- const std::map<std::string, std::string>& map2) { |
- for (const auto& val : map1) { |
- auto iter = map2.find(val.first); |
- if (iter == map2.end() || iter->second != val.second) |
- return false; |
- } |
- return true; |
-} |
- |
void ClipboardMap::UpdateFromAndroidClipboard() { |
- // Fetch the current Android clipboard state. Replace our state with |
- // the Android state if the Android state has been changed. |
+ DCHECK_NE(MapState::kPreparingCommit, map_state_); |
+ if (map_state_ == MapState::kUpToDate) |
+ return; |
+ |
+ // Fetch the current Android clipboard state. |
lock_.AssertAcquired(); |
JNIEnv* env = AttachCurrentThread(); |
- std::map<std::string, std::string> android_clipboard_state; |
- |
ScopedJavaLocalRef<jstring> jtext = |
Java_Clipboard_getCoercedText(env, clipboard_manager_); |
ScopedJavaLocalRef<jstring> jhtml = |
Java_Clipboard_getHTMLText(env, clipboard_manager_); |
- AddMapEntry(env, &android_clipboard_state, kPlainTextFormat, jtext); |
- AddMapEntry(env, &android_clipboard_state, kHTMLFormat, jhtml); |
- last_clipboard_change_time_ms_ = |
- Java_Clipboard_getClipboardContentChangeTimeInMillis(env, |
- clipboard_manager_); |
+ AddMapEntry(env, &map_, kPlainTextFormat, jtext); |
+ AddMapEntry(env, &map_, kHTMLFormat, jhtml); |
- if (!MapIsSubset(android_clipboard_state, map_)) |
- android_clipboard_state.swap(map_); |
+ map_state_ = MapState::kUpToDate; |
} |
} // namespace |
@@ -277,6 +296,13 @@ Clipboard* Clipboard::Create() { |
} |
// ClipboardAndroid implementation. |
+ |
+void ClipboardAndroid::OnPrimaryClipChanged( |
+ JNIEnv* env, |
+ const base::android::JavaParamRef<jobject>& obj) { |
+ g_map.Get().OnPrimaryClipboardChanged(); |
+} |
+ |
ClipboardAndroid::ClipboardAndroid() { |
DCHECK(CalledOnValidThread()); |
} |
@@ -289,10 +315,7 @@ void ClipboardAndroid::OnPreShutdown() {} |
uint64_t ClipboardAndroid::GetSequenceNumber(ClipboardType /* type */) const { |
DCHECK(CalledOnValidThread()); |
- // TODO: implement this. For now this interface will advertise |
- // that the clipboard never changes. That's fine as long as we |
- // don't rely on this signal. |
- return 0; |
+ return g_map.Get().GetSequenceNumber(); |
} |
bool ClipboardAndroid::IsFormatAvailable(const Clipboard::FormatType& format, |
@@ -414,10 +437,14 @@ void ClipboardAndroid::ReadData(const Clipboard::FormatType& format, |
*result = g_map.Get().Get(format.ToString()); |
} |
-base::Time ClipboardAndroid::GetClipboardLastModifiedTime() const { |
+base::Time ClipboardAndroid::GetLastModifiedTime() const { |
DCHECK(CalledOnValidThread()); |
- return base::Time::FromJavaTime( |
- g_map.Get().GetLastClipboardChangeTimeInMillis()); |
+ return g_map.Get().GetLastModifiedTime(); |
+} |
+ |
+void ClipboardAndroid::ClearLastModifiedTime() { |
+ DCHECK(CalledOnValidThread()); |
+ g_map.Get().ClearLastModifiedTime(); |
} |
// Main entry point used to write several values in the clipboard. |
@@ -485,4 +512,14 @@ void ClipboardAndroid::WriteData(const Clipboard::FormatType& format, |
g_map.Get().Set(format.ToString(), std::string(data_data, data_len)); |
} |
+bool RegisterClipboardAndroid(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+// Returns a pointer to the current ClipboardAndroid object. |
+static jlong Init(JNIEnv* env, |
+ const base::android::JavaParamRef<jobject>& obj) { |
+ return reinterpret_cast<intptr_t>(Clipboard::GetForCurrentThread()); |
+} |
+ |
} // namespace ui |