blob: 7134773610b857304ca767662672937df4249127 [file] [log] [blame]
Anders Carlssonfc309752017-06-12 14:16:20 +02001/*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "RTCUIApplicationStatusObserver.h"
12
13#if defined(WEBRTC_IOS)
14
15#import <UIKit/UIKit.h>
16
andersccca00062017-08-23 06:04:17 -070017#include "webrtc/rtc_base/checks.h"
18
andersc4090f382017-09-13 02:18:36 -070019@interface RTCUIApplicationStatusObserver ()
20
21@property(nonatomic, assign) BOOL initialized;
22@property(nonatomic, assign) UIApplicationState state;
23
24@end
25
Anders Carlssonfc309752017-06-12 14:16:20 +020026@implementation RTCUIApplicationStatusObserver {
andersccca00062017-08-23 06:04:17 -070027 BOOL _initialized;
28 dispatch_block_t _initializeBlock;
andersc9a85f072017-09-13 07:31:46 -070029 dispatch_semaphore_t _waitForInitializeSemaphore;
Anders Carlssonfc309752017-06-12 14:16:20 +020030 UIApplicationState _state;
andersc4090f382017-09-13 02:18:36 -070031
32 id<NSObject> _activeObserver;
33 id<NSObject> _backgroundObserver;
Anders Carlssonfc309752017-06-12 14:16:20 +020034}
35
andersc4090f382017-09-13 02:18:36 -070036@synthesize initialized = _initialized;
37@synthesize state = _state;
38
Anders Carlssonfc309752017-06-12 14:16:20 +020039+ (instancetype)sharedInstance {
40 static id sharedInstance;
41 static dispatch_once_t onceToken;
42 dispatch_once(&onceToken, ^{
43 sharedInstance = [[self alloc] init];
44 });
45
46 return sharedInstance;
47}
48
andersc9a85f072017-09-13 07:31:46 -070049// Method to make sure observers are added and the initialization block is
50// scheduled to run on the main queue.
51+ (void)prepareForUse {
52 __unused RTCUIApplicationStatusObserver *observer = [self sharedInstance];
53}
54
Anders Carlssonfc309752017-06-12 14:16:20 +020055- (id)init {
56 if (self = [super init]) {
57 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
andersc4090f382017-09-13 02:18:36 -070058 __weak RTCUIApplicationStatusObserver *weakSelf = self;
59 _activeObserver = [center addObserverForName:UIApplicationDidBecomeActiveNotification
60 object:nil
61 queue:[NSOperationQueue mainQueue]
62 usingBlock:^(NSNotification *note) {
63 weakSelf.state =
64 [UIApplication sharedApplication].applicationState;
65 }];
Anders Carlssonfc309752017-06-12 14:16:20 +020066
andersc4090f382017-09-13 02:18:36 -070067 _backgroundObserver = [center addObserverForName:UIApplicationDidEnterBackgroundNotification
68 object:nil
69 queue:[NSOperationQueue mainQueue]
70 usingBlock:^(NSNotification *note) {
71 weakSelf.state =
72 [UIApplication sharedApplication].applicationState;
73 }];
Anders Carlssonfc309752017-06-12 14:16:20 +020074
andersc9a85f072017-09-13 07:31:46 -070075 _waitForInitializeSemaphore = dispatch_semaphore_create(1);
andersccca00062017-08-23 06:04:17 -070076 _initialized = NO;
77 _initializeBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
andersc4090f382017-09-13 02:18:36 -070078 weakSelf.state = [UIApplication sharedApplication].applicationState;
79 weakSelf.initialized = YES;
andersccca00062017-08-23 06:04:17 -070080 });
Anders Carlssonfc309752017-06-12 14:16:20 +020081
andersccca00062017-08-23 06:04:17 -070082 dispatch_async(dispatch_get_main_queue(), _initializeBlock);
Anders Carlssonfc309752017-06-12 14:16:20 +020083 }
84
85 return self;
86}
87
andersc4090f382017-09-13 02:18:36 -070088- (void)dealloc {
89 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
90 [center removeObserver:_activeObserver];
91 [center removeObserver:_backgroundObserver];
92}
93
Anders Carlssonfc309752017-06-12 14:16:20 +020094- (BOOL)isApplicationActive {
andersc9a85f072017-09-13 07:31:46 -070095 // NOTE: The function `dispatch_block_wait` can only legally be called once.
96 // Because of this, if several threads call the `isApplicationActive` method before
97 // the `_initializeBlock` has been executed, instead of multiple threads calling
98 // `dispatch_block_wait`, the other threads need to wait for the first waiting thread
99 // instead.
andersccca00062017-08-23 06:04:17 -0700100 if (!_initialized) {
andersc9a85f072017-09-13 07:31:46 -0700101 dispatch_semaphore_wait(_waitForInitializeSemaphore, DISPATCH_TIME_FOREVER);
102 if (!_initialized) {
103 long ret = dispatch_block_wait(_initializeBlock,
104 dispatch_time(DISPATCH_TIME_NOW, 10.0 * NSEC_PER_SEC));
105 RTC_DCHECK_EQ(ret, 0);
106 }
107 dispatch_semaphore_signal(_waitForInitializeSemaphore);
andersccca00062017-08-23 06:04:17 -0700108 }
Anders Carlssonfc309752017-06-12 14:16:20 +0200109 return _state == UIApplicationStateActive;
110}
111
112@end
113
114#endif // WEBRTC_IOS