Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(257)

Unified Diff: ios/chrome/today_extension/lock_screen_state.mm

Issue 2586713002: Upstream code and resources for Chrome on iOS extensions. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/today_extension/lock_screen_state.mm
diff --git a/ios/chrome/today_extension/lock_screen_state.mm b/ios/chrome/today_extension/lock_screen_state.mm
new file mode 100644
index 0000000000000000000000000000000000000000..f7da4c64ea2126f9bc1498150e05d5380f1aa9c9
--- /dev/null
+++ b/ios/chrome/today_extension/lock_screen_state.mm
@@ -0,0 +1,197 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/today_extension/lock_screen_state.h"
+
+#import <UIKit/UIKit.h>
+
+#import "base/ios/weak_nsobject.h"
+
+namespace {
+
+// Name of the protected file used to detect if extension is triggered on lock
+// screen.
+NSString* const kLockScreenFileName = @"LockScreenDetector";
+
+// Return the path of a file that will always have NSFileProtectionComplete
+// protection option. This file cannot be accessed from the lock screen and can
+// be used to detect if the device is locked.
+NSString* LockedDeviceFilename() {
+ NSString* path = [NSSearchPathForDirectoriesInDomains(
+ NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+ return [path stringByAppendingPathComponent:kLockScreenFileName];
+}
+
+} // namespace
+
+@interface LockScreenState ()
+
+- (instancetype)init;
+
+// Returns if the protected file is accessible.
+// Note: the function tests the access to protected file. Access is revoked 10
+// seconds after screen is locked. So this method returns YES if screen has been
+// locked for more than 10 seconds.
+// Returns NO if CreateLockScreenDetector has never been called.
+- (BOOL)isProtectedFileAccessible;
+
+// Periodically checks (every second) if the protected file is still accessible.
+// Checks |remainingTests| times.
+- (void)recheckProtectedFile:(int)remainingTests;
+
+// Creates a protected file that will be used to detect if screen is locked.
+- (void)createLockScreenDetector;
+
+@end
+
+@implementation LockScreenState {
+ id<LockScreenStateDelegate> _delegate;
+ BOOL _screenLocked;
+ BOOL _lockScreenStateKnown;
+ BOOL _protectedFileCreated;
+}
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(screenLocked:)
+ name:UIApplicationProtectedDataWillBecomeUnavailable
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(screenUnlocked:)
+ name:UIApplicationProtectedDataDidBecomeAvailable
+ object:nil];
+ _delegate = nil;
+ }
+ return self;
+}
+
++ (instancetype)sharedInstance {
+ static LockScreenState* instance = [[LockScreenState alloc] init];
+ return instance;
+}
+
+- (void)screenLocked:(id)arguments {
+ _screenLocked = YES;
+ _lockScreenStateKnown = YES;
+ [_delegate lockScreenStateDidChange:self];
+}
+
+- (void)screenUnlocked:(id)arguments {
+ _screenLocked = NO;
+ _lockScreenStateKnown = YES;
+ [_delegate lockScreenStateDidChange:self];
+}
+
+- (void)setDelegate:(id)delegate {
+ _delegate = delegate;
+}
+
+- (BOOL)isScreenLocked {
+ if (_lockScreenStateKnown) {
+ return _screenLocked;
+ }
+ [self createLockScreenDetector];
+ if (!_protectedFileCreated) {
+ // File could not be created. Screen is locked.
+ _screenLocked = YES;
+ _lockScreenStateKnown = YES;
+ return YES;
+ }
+ _screenLocked = ![self isProtectedFileAccessible];
+ _lockScreenStateKnown = YES;
+
+ if (!_screenLocked) {
+ // This test is only valid if screen has been locked for more than 10
+ // seconds (https://www.apple.com/business/docs/iOS_Security_Guide.pdf).
+ // In that case, no notification is received after the delay.
+ // Reschedule tests every second for 15 seconds.
+ base::WeakNSObject<LockScreenState> weakSelf(self);
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ static_cast<int64_t>(1 * NSEC_PER_SEC)),
+ dispatch_get_main_queue(), ^{
+ [weakSelf recheckProtectedFile:14];
+ });
+ }
+ return _screenLocked;
+}
+
+- (void)recheckProtectedFile:(int)remainingTests {
+ BOOL screenLocked = ![self isProtectedFileAccessible];
+ if (screenLocked) {
+ // |_screenLocked| may already be set to YES if we received a notification.
+ if (!_screenLocked) {
+ _screenLocked = YES;
+ [_delegate lockScreenStateDidChange:self];
+ }
+ return;
+ }
+ if (remainingTests) {
+ base::WeakNSObject<LockScreenState> weakSelf(self);
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ static_cast<int64_t>(1 * NSEC_PER_SEC)),
+ dispatch_get_main_queue(), ^{
+ [weakSelf recheckProtectedFile:remainingTests - 1];
+ });
+ }
+}
+
+- (BOOL)isProtectedFileAccessible {
+ NSError* error = nil;
+ if (![[NSFileManager defaultManager]
+ fileExistsAtPath:LockedDeviceFilename()]) {
+ return NO;
+ }
+ [NSData dataWithContentsOfFile:LockedDeviceFilename()
+ options:NSDataReadingMappedIfSafe
+ error:&error];
+ return !error;
+}
+
+- (void)createLockScreenDetector {
+ if (_protectedFileCreated)
+ return;
+ NSError* error = nil;
+ if ([[NSFileManager defaultManager]
+ fileExistsAtPath:LockedDeviceFilename()]) {
+ NSDictionary* attributes = [[NSFileManager defaultManager]
+ attributesOfItemAtPath:LockedDeviceFilename()
+ error:&error];
+ if ([[attributes valueForKey:NSFileProtectionKey]
+ isEqualToString:NSFileProtectionComplete]) {
+ _protectedFileCreated = YES;
+ return;
+ }
+ BOOL removed =
+ [[NSFileManager defaultManager] removeItemAtPath:LockedDeviceFilename()
+ error:&error];
+ if (!removed || error) {
+ // File could not be removed. FileSystem may be locked ?
+ return;
+ }
+ }
+ BOOL created = [[NSFileManager defaultManager]
+ createFileAtPath:LockedDeviceFilename()
+ contents:[@"Unlock" dataUsingEncoding:NSUTF8StringEncoding]
+ attributes:@{NSFileProtectionKey : NSFileProtectionComplete}];
+ if (!created) {
+ // File could not be created. FileSystem may be locked ?
+ return;
+ }
+ NSDictionary* attributes = [[NSFileManager defaultManager]
+ attributesOfItemAtPath:LockedDeviceFilename()
+ error:&error];
+ if ([[attributes valueForKey:NSFileProtectionKey]
+ isEqualToString:NSFileProtectionComplete]) {
+ _protectedFileCreated = YES;
+ return;
+ }
+ [[NSFileManager defaultManager] removeItemAtPath:LockedDeviceFilename()
+ error:&error];
+}
+
+@end
« no previous file with comments | « ios/chrome/today_extension/lock_screen_state.h ('k') | ios/chrome/today_extension/notification_center_button.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698