| 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
|
|
|