| Index: components/open_from_clipboard/clipboard_recent_content_ios.mm
|
| diff --git a/components/open_from_clipboard/clipboard_recent_content_ios.mm b/components/open_from_clipboard/clipboard_recent_content_ios.mm
|
| index 6d7d874c4bcf652d0ec09b56cf9a294db9da2d23..930a2747fdb6bb00f0c8aa5a79517b0615e3cee4 100644
|
| --- a/components/open_from_clipboard/clipboard_recent_content_ios.mm
|
| +++ b/components/open_from_clipboard/clipboard_recent_content_ios.mm
|
| @@ -15,221 +15,78 @@
|
| #include "base/metrics/user_metrics.h"
|
| #include "base/strings/sys_string_conversions.h"
|
| #include "base/sys_info.h"
|
| +#import "components/open_from_clipboard/clipboard_recent_content_impl_ios.h"
|
| +#import "net/base/mac/url_conversions.h"
|
| #include "url/gurl.h"
|
| +#include "url/url_constants.h"
|
|
|
| -// Bridge that forwards UIApplicationDidBecomeActiveNotification notifications
|
| -// to its delegate.
|
| -@interface ApplicationDidBecomeActiveNotificationListenerBridge : NSObject
|
| -
|
| -// Initialize the ApplicationDidBecomeActiveNotificationListenerBridge with
|
| -// |delegate| which must not be null.
|
| -- (instancetype)initWithDelegate:(ClipboardRecentContentIOS*)delegate
|
| - NS_DESIGNATED_INITIALIZER;
|
| -
|
| -- (instancetype)init NS_UNAVAILABLE;
|
| -
|
| -@end
|
| -
|
| -@implementation ApplicationDidBecomeActiveNotificationListenerBridge {
|
| - ClipboardRecentContentIOS* _delegate;
|
| -}
|
| -
|
| -- (instancetype)init {
|
| - NOTREACHED();
|
| - return nil;
|
| -}
|
| +namespace {
|
|
|
| -- (instancetype)initWithDelegate:(ClipboardRecentContentIOS*)delegate {
|
| - DCHECK(delegate);
|
| - self = [super init];
|
| - if (self) {
|
| - _delegate = delegate;
|
| - [[NSNotificationCenter defaultCenter]
|
| - addObserver:self
|
| - selector:@selector(didBecomeActive:)
|
| - name:UIApplicationDidBecomeActiveNotification
|
| - object:nil];
|
| +// Schemes accepted by the ClipboardRecentContentIOS.
|
| +const char* kAuthorizedSchemes[] = {
|
| + url::kHttpScheme, url::kHttpsScheme, url::kDataScheme, url::kAboutScheme,
|
| +};
|
| +
|
| +// Get the list of authorized schemes.
|
| +NSSet<NSString*>* getAuthorizedSchemeList(
|
| + const std::string& application_scheme) {
|
| + NSMutableSet<NSString*>* schemes = [NSMutableSet set];
|
| + for (size_t i = 0; i < arraysize(kAuthorizedSchemes); ++i) {
|
| + [schemes addObject:base::SysUTF8ToNSString(kAuthorizedSchemes[i])];
|
| }
|
| - return self;
|
| -}
|
| -
|
| -- (void)dealloc {
|
| - [[NSNotificationCenter defaultCenter] removeObserver:self];
|
| - [super dealloc];
|
| -}
|
| -
|
| -- (void)didBecomeActive:(NSNotification*)notification {
|
| - if (_delegate) {
|
| - _delegate->LoadFromUserDefaults();
|
| - _delegate->UpdateIfNeeded();
|
| + if (!application_scheme.empty()) {
|
| + [schemes addObject:base::SysUTF8ToNSString(application_scheme)];
|
| }
|
| -}
|
|
|
| -- (void)disconnect {
|
| - _delegate = nullptr;
|
| -}
|
| -
|
| -@end
|
| -
|
| -namespace {
|
| -// Key used to store the pasteboard's current change count. If when resuming
|
| -// chrome the pasteboard's change count is different from the stored one, then
|
| -// it means that the pasteboard's content has changed.
|
| -NSString* kPasteboardChangeCountKey = @"PasteboardChangeCount";
|
| -// Key used to store the last date at which it was detected that the pasteboard
|
| -// changed. It is used to evaluate the age of the pasteboard's content.
|
| -NSString* kPasteboardChangeDateKey = @"PasteboardChangeDate";
|
| -// Key used to store the hash of the content of the pasteboard. Whenever the
|
| -// hash changed, the pasteboard content is considered to have changed.
|
| -NSString* kPasteboardEntryMD5Key = @"PasteboardEntryMD5";
|
| -
|
| -// Compute a hash consisting of the first 4 bytes of the MD5 hash of |string|.
|
| -// This value is used to detect pasteboard content change. Keeping only 4 bytes
|
| -// is a privacy requirement to introduce collision and allow deniability of
|
| -// having copied a given string.
|
| -NSData* WeakMD5FromNSString(NSString* string) {
|
| - unsigned char hash[CC_MD5_DIGEST_LENGTH];
|
| - const std::string clipboard = base::SysNSStringToUTF8(string);
|
| - const char* c_string = clipboard.c_str();
|
| - CC_MD5(c_string, strlen(c_string), hash);
|
| - NSData* data = [NSData dataWithBytes:hash length:4];
|
| - return data;
|
| + return [schemes copy];
|
| }
|
|
|
| } // namespace
|
|
|
| -bool ClipboardRecentContentIOS::GetRecentURLFromClipboard(GURL* url) {
|
| - DCHECK(url);
|
| - UpdateIfNeeded();
|
| - if (GetClipboardContentAge() > kMaximumAgeOfClipboard) {
|
| - return false;
|
| - }
|
| -
|
| - GURL url_from_pasteboard = URLFromPasteboard();
|
| - if (url_from_pasteboard.is_valid()) {
|
| - *url = url_from_pasteboard;
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| +@interface ClipboardRecentContentDelegateImpl
|
| + : NSObject<ClipboardRecentContentDelegate>
|
| +@end
|
|
|
| -base::TimeDelta ClipboardRecentContentIOS::GetClipboardContentAge() const {
|
| - return base::TimeDelta::FromSeconds(static_cast<int64_t>(
|
| - -[last_pasteboard_change_date_ timeIntervalSinceNow]));
|
| -}
|
| +@implementation ClipboardRecentContentDelegateImpl
|
|
|
| -void ClipboardRecentContentIOS::SuppressClipboardContent() {
|
| - // User cleared the user data. The pasteboard entry must be removed from the
|
| - // omnibox list. Force entry expiration by setting copy date to 1970.
|
| - last_pasteboard_change_date_.reset(
|
| - [[NSDate alloc] initWithTimeIntervalSince1970:0]);
|
| - SaveToUserDefaults();
|
| +- (void)onClipboardChanged {
|
| + base::RecordAction(base::UserMetricsAction("MobileOmniboxClipboardChanged"));
|
| }
|
|
|
| -void ClipboardRecentContentIOS::UpdateIfNeeded() {
|
| - if (!HasPasteboardChanged())
|
| - return;
|
| -
|
| - base::RecordAction(base::UserMetricsAction("MobileClipboardChanged"));
|
| -
|
| - GURL url_from_pasteboard = URLFromPasteboard();
|
| - last_pasteboard_change_date_.reset([[NSDate date] retain]);
|
| - last_pasteboard_change_count_ = [UIPasteboard generalPasteboard].changeCount;
|
| - NSString* pasteboard_string = [[UIPasteboard generalPasteboard] string];
|
| - if (!pasteboard_string) {
|
| - pasteboard_string = @"";
|
| - }
|
| - NSData* MD5 = WeakMD5FromNSString(pasteboard_string);
|
| - last_pasteboard_entry_md5_.reset([MD5 retain]);
|
| - SaveToUserDefaults();
|
| -}
|
| +@end
|
|
|
| ClipboardRecentContentIOS::ClipboardRecentContentIOS(
|
| const std::string& application_scheme,
|
| NSUserDefaults* group_user_defaults)
|
| - : application_scheme_(application_scheme),
|
| - shared_user_defaults_([group_user_defaults retain]) {
|
| - last_pasteboard_change_count_ = NSIntegerMax;
|
| - LoadFromUserDefaults();
|
| -
|
| - UpdateIfNeeded();
|
| -
|
| - // Makes sure |last_pasteboard_change_count_| was properly initialized.
|
| - DCHECK_NE(last_pasteboard_change_count_, NSIntegerMax);
|
| - notification_bridge_.reset(
|
| - [[ApplicationDidBecomeActiveNotificationListenerBridge alloc]
|
| - initWithDelegate:this]);
|
| -}
|
| -
|
| -bool ClipboardRecentContentIOS::HasPasteboardChanged() const {
|
| - // If |MD5Changed|, we know for sure there has been at least one pasteboard
|
| - // copy since last time it was checked.
|
| - // If the pasteboard content is still the same but the device was not
|
| - // rebooted, the change count can be checked to see if it changed.
|
| - // Note: due to a mismatch between the actual behavior and documentation, and
|
| - // lack of consistency on different reboot scenarios, the change count cannot
|
| - // be checked after a reboot.
|
| - // See radar://21833556 for more information.
|
| - NSInteger change_count = [UIPasteboard generalPasteboard].changeCount;
|
| - bool change_count_changed = change_count != last_pasteboard_change_count_;
|
| -
|
| - bool not_rebooted = Uptime() > GetClipboardContentAge();
|
| - if (not_rebooted)
|
| - return change_count_changed;
|
| -
|
| - NSString* pasteboard_string = [[UIPasteboard generalPasteboard] string];
|
| - if (!pasteboard_string) {
|
| - pasteboard_string = @"";
|
| - }
|
| - NSData* md5 = WeakMD5FromNSString(pasteboard_string);
|
| - BOOL md5_changed = ![md5 isEqualToData:last_pasteboard_entry_md5_];
|
| + : ClipboardRecentContentIOS([[ClipboardRecentContentImplIOS alloc]
|
| + initWithAuthorizedSchemes:getAuthorizedSchemeList(application_scheme)
|
| + userDefaults:group_user_defaults
|
| + delegate:[[ClipboardRecentContentDelegateImpl alloc]
|
| + init]]) {}
|
|
|
| - return md5_changed;
|
| -}
|
| -
|
| -ClipboardRecentContentIOS::~ClipboardRecentContentIOS() {
|
| - [notification_bridge_ disconnect];
|
| +ClipboardRecentContentIOS::ClipboardRecentContentIOS(
|
| + ClipboardRecentContentImplIOS* implementation) {
|
| + implementation_.reset(implementation);
|
| }
|
|
|
| -GURL ClipboardRecentContentIOS::URLFromPasteboard() {
|
| - NSString* clipboard_string = [[UIPasteboard generalPasteboard] string];
|
| - if (!clipboard_string) {
|
| - return GURL::EmptyGURL();
|
| - }
|
| - const std::string clipboard = base::SysNSStringToUTF8(clipboard_string);
|
| - GURL gurl = GURL(clipboard);
|
| - if (gurl.is_valid()) {
|
| - if (IsAppropriateSuggestion(gurl))
|
| - return gurl;
|
| - if (!application_scheme_.empty() &&
|
| - gurl.SchemeIs(application_scheme_.c_str())) {
|
| - return gurl;
|
| - }
|
| +bool ClipboardRecentContentIOS::GetRecentURLFromClipboard(GURL* url) {
|
| + DCHECK(url);
|
| + NSURL* url_from_pasteboard = [implementation_ recentURLFromClipboard];
|
| + GURL converted_url = net::GURLWithNSURL(url_from_pasteboard);
|
| + if (converted_url.is_valid()) {
|
| + *url = std::move(converted_url);
|
| + return true;
|
| }
|
| - return GURL::EmptyGURL();
|
| + return false;
|
| }
|
|
|
| -void ClipboardRecentContentIOS::LoadFromUserDefaults() {
|
| - last_pasteboard_change_count_ =
|
| - [shared_user_defaults_ integerForKey:kPasteboardChangeCountKey];
|
| - last_pasteboard_change_date_.reset(
|
| - [[shared_user_defaults_ objectForKey:kPasteboardChangeDateKey] retain]);
|
| - last_pasteboard_entry_md5_.reset(
|
| - [[shared_user_defaults_ objectForKey:kPasteboardEntryMD5Key] retain]);
|
| -
|
| - DCHECK(!last_pasteboard_change_date_ ||
|
| - [last_pasteboard_change_date_ isKindOfClass:[NSDate class]]);
|
| -}
|
| +ClipboardRecentContentIOS::~ClipboardRecentContentIOS() {}
|
|
|
| -void ClipboardRecentContentIOS::SaveToUserDefaults() {
|
| - [shared_user_defaults_ setInteger:last_pasteboard_change_count_
|
| - forKey:kPasteboardChangeCountKey];
|
| - [shared_user_defaults_ setObject:last_pasteboard_change_date_
|
| - forKey:kPasteboardChangeDateKey];
|
| - [shared_user_defaults_ setObject:last_pasteboard_entry_md5_
|
| - forKey:kPasteboardEntryMD5Key];
|
| +base::TimeDelta ClipboardRecentContentIOS::GetClipboardContentAge() const {
|
| + return base::TimeDelta::FromSeconds(
|
| + static_cast<int64_t>([implementation_ clipboardContentAge]));
|
| }
|
|
|
| -base::TimeDelta ClipboardRecentContentIOS::Uptime() const {
|
| - return base::SysInfo::Uptime();
|
| +void ClipboardRecentContentIOS::SuppressClipboardContent() {
|
| + [implementation_ suppressClipboardContent];
|
| }
|
|
|