Commit a79912e5 authored by edchin's avatar edchin Committed by Commit Bot

[ios] Add ScreenTime coordinator/mediator/view_controller

This CL makes the ScreenTime blocking view work fully.

* Creates a ScreenTimeCoordinator in the BrowserContainerCoordinator.
* Creates a ScreenTimeViewController as a contained view controller
inside the BrowserContainerViewController.
* Creates a ScreenTimeMediator, which is responsible for updating the
ScreenTime system with the active WebState's URL.

Bug: 1123704
Change-Id: I5dd9af8575baf2560ab7abb42d45628d32c6990b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2391798
Commit-Queue: edchin <edchin@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Reviewed-by: default avatarGauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804569}
parent a3aa1ad4
......@@ -20,6 +20,8 @@ source_set("browser_container") {
"//ios/chrome/browser/overlays/public/web_content_area",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/ui/overlays",
"//ios/chrome/browser/ui/screen_time",
"//ios/chrome/browser/ui/screen_time:feature_flags",
"//ios/chrome/browser/web_state_list",
"//ios/web/public",
"//url",
......
......@@ -23,6 +23,10 @@
- (void)setWebContentsOverlayContainerViewController:
(UIViewController*)webContentsOverlayContainerViewController;
// The UIViewController used to display the ScreenTime UI above the web content
// area.
- (void)setScreenTimeViewController:(UIViewController*)screenTimeViewController;
// Whether the content view should be blocked. When set to YES, the content
// area is blocked. Overlay UI shown in OverlayModality::kWebContentArea remain
// visible when |contentBlocked| is YES.
......
......@@ -10,6 +10,8 @@
#import "ios/chrome/browser/ui/browser_container/browser_container_mediator.h"
#import "ios/chrome/browser/ui/browser_container/browser_container_view_controller.h"
#import "ios/chrome/browser/ui/overlays/overlay_container_coordinator.h"
#import "ios/chrome/browser/ui/screen_time/features.h"
#import "ios/chrome/browser/ui/screen_time/screen_time_coordinator.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
......@@ -27,6 +29,8 @@
// The overlay container coordinator for OverlayModality::kWebContentArea.
@property(nonatomic, strong)
OverlayContainerCoordinator* webContentAreaOverlayContainerCoordinator;
// The coodinator that manages ScreenTime.
@property(nonatomic, strong) ChromeCoordinator* screenTimeCoordinator;
@end
@implementation BrowserContainerCoordinator
......@@ -55,6 +59,8 @@
webContentAreaOverlayPresenter:overlayPresenter];
self.mediator.consumer = self.viewController;
[self setUpScreenTimeIfEnabled];
[super start];
}
......@@ -63,9 +69,30 @@
return;
self.started = NO;
[self.webContentAreaOverlayContainerCoordinator stop];
[self.screenTimeCoordinator stop];
self.viewController = nil;
self.mediator = nil;
[super stop];
}
#pragma mark - Private methods
// Sets up the ScreenTime coordinator, which installs and manages the ScreenTime
// blocking view.
- (void)setUpScreenTimeIfEnabled {
if (!IsScreenTimeIntegrationEnabled())
return;
if (@available(iOS 14, *)) {
ScreenTimeCoordinator* screenTimeCoordinator =
[[ScreenTimeCoordinator alloc]
initWithBaseViewController:self.viewController
browser:self.browser];
[screenTimeCoordinator start];
self.viewController.screenTimeViewController =
screenTimeCoordinator.viewController;
self.screenTimeCoordinator = screenTimeCoordinator;
}
}
@end
......@@ -31,6 +31,7 @@ using base::test::ios::kWaitForUIElementTimeout;
@property(nonatomic, strong) UIViewController* contentViewController;
@property(nonatomic, strong)
UIViewController* webContentsOverlayContainerViewController;
@property(nonatomic, strong) UIViewController* screenTimeViewController;
@property(nonatomic, assign, getter=isContentBlocked) BOOL contentBlocked;
@end
......
......@@ -17,6 +17,11 @@
@property(nonatomic, strong, readonly)
UIViewController* webContentsOverlayContainerViewController;
// The UIViewController used to display the ScreenTime blocker above the web
// content area.
@property(nonatomic, strong, readonly)
UIViewController* screenTimeViewController;
@end
#endif // IOS_CHROME_BROWSER_UI_BROWSER_CONTAINER_BROWSER_CONTAINER_VIEW_CONTROLLER_H_
......@@ -17,6 +17,7 @@
@property(nonatomic, strong) UIViewController* contentViewController;
@property(nonatomic, strong)
UIViewController* webContentsOverlayContainerViewController;
@property(nonatomic, strong) UIViewController* screenTimeViewController;
@property(nonatomic, assign, getter=isContentBlocked) BOOL contentBlocked;
// The view inserted into the hierarchy when self.contentBlocked is set to YES.
@property(nonatomic, strong) UIView* contentBlockingView;
......@@ -37,9 +38,11 @@
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
// OverlayContainerView should cover all subviews of BrowserContainerView.
// OverlayContainerView should cover all subviews of BrowserContainerView. The
// ScreenTime container must be above the WebContentArea overlay container.
[self.view
bringSubviewToFront:self.webContentsOverlayContainerViewController.view];
[self.view bringSubviewToFront:self.screenTimeViewController.view];
}
- (void)dismissViewControllerAnimated:(BOOL)animated
......
......@@ -2836,6 +2836,12 @@ NSString* const kBrowserViewControllerSnackbarCategory =
[overlays addObject:presentedOverlayView];
}
UIView* screenTimeView =
self.browserContainerViewController.screenTimeViewController.view;
if (screenTimeView) {
[overlays addObject:screenTimeView];
}
UIView* childOverlayView =
overlayContainerViewController.childViewControllers.firstObject.view;
if (childOverlayView) {
......
......@@ -2,6 +2,34 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
source_set("screen_time") {
sources = [
"screen_time_consumer.h",
"screen_time_coordinator.h",
"screen_time_coordinator.mm",
"screen_time_mediator.h",
"screen_time_mediator.mm",
"screen_time_view_controller.h",
"screen_time_view_controller.mm",
]
frameworks = [
"ScreenTime.framework",
"UIKit.framework",
]
configs += [ "//build/config/compiler:enable_arc" ]
deps = [
":feature_flags",
"//base",
"//ios/chrome/browser/browser_state",
"//ios/chrome/browser/main:public",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators",
"//ios/chrome/browser/web_state_list",
"//ios/chrome/common/ui/util",
"//ios/web/public",
"//net",
]
}
source_set("feature_flags") {
sources = [
"features.h",
......
// Copyright 2020 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.
#ifndef IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_CONSUMER_H_
#define IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_CONSUMER_H_
#import <Foundation/Foundation.h>
// A protocol to update information reported to the ScreenTime system.
@protocol ScreenTimeConsumer
// Sets |URL| as the active URL reported to the ScreenTime system when the
// underlying web view is visible.
- (void)setURL:(NSURL*)URL;
// Disables usage recording in the ScreenTime system.
- (void)setSuppressUsageRecording:(BOOL)suppressUsageRecording;
@end
#endif // IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_CONSUMER_H_
// Copyright 2020 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.
#ifndef IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_COORDINATOR_H_
#define IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_COORDINATOR_H_
#import <Foundation/Foundation.h>
#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
// This coordinator encapsulates the integration to ScreenTime, reporting web
// usage and blocking restricted webpages.
API_AVAILABLE(ios(14.0))
@interface ScreenTimeCoordinator : ChromeCoordinator
// The view controller that must be placed above the web view to enable web
// usage reporting. This view controller automatically blocks when the reported
// URL becomes restricted.
@property(nonatomic, readonly) UIViewController* viewController;
@end
#endif // IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_COORDINATOR_H_
// Copyright 2020 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/browser/ui/screen_time/screen_time_coordinator.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/ui/screen_time/screen_time_mediator.h"
#import "ios/chrome/browser/ui/screen_time/screen_time_view_controller.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface ScreenTimeCoordinator ()
@property(nonatomic, strong) ScreenTimeViewController* screenTimeViewController;
@property(nonatomic, strong) ScreenTimeMediator* mediator;
@end
@implementation ScreenTimeCoordinator
#pragma mark - Public properties
- (UIViewController*)viewController {
return self.screenTimeViewController;
}
#pragma mark - ChromeCoordinator
- (void)start {
self.screenTimeViewController = [[ScreenTimeViewController alloc] init];
self.mediator = [[ScreenTimeMediator alloc]
initWithWebStateList:self.browser->GetWebStateList()
suppressUsageRecording:self.browser->GetBrowserState()->IsOffTheRecord()];
}
- (void)stop {
self.mediator = nil;
self.screenTimeViewController = nil;
}
#pragma mark - Private properties
- (void)setMediator:(ScreenTimeMediator*)mediator {
if (_mediator == mediator)
return;
if (_mediator) {
[_mediator disconnect];
_mediator = nil;
}
if (mediator) {
DCHECK_NE(nil, self.screenTimeViewController);
_mediator = mediator;
_mediator.consumer = self.screenTimeViewController;
}
}
- (void)setScreenTimeViewController:
(ScreenTimeViewController*)screenTimeViewController {
if (_screenTimeViewController == screenTimeViewController)
return;
if (_screenTimeViewController) {
[_screenTimeViewController willMoveToParentViewController:nil];
[_screenTimeViewController.view removeFromSuperview];
[_screenTimeViewController removeFromParentViewController];
_screenTimeViewController = nil;
}
if (screenTimeViewController) {
DCHECK_NE(nil, self.baseViewController);
UIView* screenTimeView = screenTimeViewController.view;
screenTimeView.translatesAutoresizingMaskIntoConstraints = NO;
[self.baseViewController addChildViewController:screenTimeViewController];
[self.baseViewController.view addSubview:screenTimeView];
AddSameConstraints(screenTimeView, self.baseViewController.view);
[screenTimeViewController
didMoveToParentViewController:self.baseViewController];
_screenTimeViewController = screenTimeViewController;
}
}
@end
// Copyright 2020 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.
#ifndef IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_MEDIATOR_H_
#define IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_MEDIATOR_H_
#import <Foundation/Foundation.h>
@protocol ScreenTimeConsumer;
class WebStateList;
// This mediator manages reporting the active WebState's visible URL to the
// ScreenTime system.
@interface ScreenTimeMediator : NSObject
@property(nonatomic, weak) id<ScreenTimeConsumer> consumer;
// This mediator reports information from |webStateList| to the ScreenTime
// system. Recording is disabled if |suppressUsageRecording| is YES.
- (instancetype)initWithWebStateList:(WebStateList*)webStateList
suppressUsageRecording:(BOOL)suppressUsageRecording
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// Stops observing all objects.
- (void)disconnect;
@end
#endif // IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_MEDIATOR_H_
// Copyright 2020 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/browser/ui/screen_time/screen_time_mediator.h"
#import "ios/chrome/browser/main/browser.h"
#import "ios/chrome/browser/ui/screen_time/screen_time_consumer.h"
#import "ios/chrome/browser/web_state_list/active_web_state_observation_forwarder.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
#import "ios/web/public/web_state.h"
#import "ios/web/public/web_state_observer_bridge.h"
#include "net/base/mac/url_conversions.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface ScreenTimeMediator () <WebStateListObserving, CRWWebStateObserver> {
std::unique_ptr<WebStateListObserver> _webStateListObserver;
std::unique_ptr<web::WebStateObserverBridge> _observer;
std::unique_ptr<ActiveWebStateObservationForwarder> _forwarder;
}
// This class updates ScreenTime with information from this WebStateList.
@property(nonatomic, assign, readonly) WebStateList* webStateList;
// Whether ScreenTime should be recording web usage.
@property(nonatomic, assign, readonly) BOOL suppressUsageRecording;
@end
@implementation ScreenTimeMediator
- (instancetype)initWithWebStateList:(WebStateList*)webStateList
suppressUsageRecording:(BOOL)suppressUsageRecording {
self = [super init];
if (self) {
DCHECK(webStateList);
_webStateList = webStateList;
_webStateListObserver = std::make_unique<WebStateListObserverBridge>(self);
_webStateList->AddObserver(_webStateListObserver.get());
_observer = std::make_unique<web::WebStateObserverBridge>(self);
_forwarder = std::make_unique<ActiveWebStateObservationForwarder>(
webStateList, _observer.get());
_suppressUsageRecording = suppressUsageRecording;
}
return self;
}
- (void)dealloc {
// |-disconnect| must be called before deallocation.
DCHECK(!_webStateList);
}
- (void)disconnect {
if (self.webStateList) {
self.webStateList->RemoveObserver(_webStateListObserver.get());
_webStateListObserver = nullptr;
_webStateList = nullptr;
_forwarder = nullptr;
_observer = nullptr;
}
}
#pragma mark - Public properties
- (void)setConsumer:(id<ScreenTimeConsumer>)consumer {
_consumer = consumer;
[consumer setSuppressUsageRecording:self.suppressUsageRecording];
[self updateConsumer];
}
#pragma mark - WebStateListObserver
- (void)webStateList:(WebStateList*)webStateList
didReplaceWebState:(web::WebState*)oldWebState
withWebState:(web::WebState*)newWebState
atIndex:(int)atIndex {
DCHECK_EQ(self.webStateList, webStateList);
[self updateConsumer];
}
- (void)webStateList:(WebStateList*)webStateList
didChangeActiveWebState:(web::WebState*)newWebState
oldWebState:(web::WebState*)oldWebState
atIndex:(int)atIndex
reason:(ActiveWebStateChangeReason)reason {
DCHECK_EQ(self.webStateList, webStateList);
[self updateConsumer];
}
#pragma mark - CRWWebStateObserver
- (void)webState:(web::WebState*)webState
didFinishNavigation:(web::NavigationContext*)navigation {
[self updateConsumer];
}
- (void)webStateDestroyed:(web::WebState*)webState {
[self updateConsumer];
}
- (void)renderProcessGoneForWebState:(web::WebState*)webState {
[self updateConsumer];
}
#pragma mark - Private methods
- (void)updateConsumer {
DCHECK(self.consumer);
NSURL* activeURL = nil;
web::WebState* activeWebState = self.webStateList->GetActiveWebState();
if (activeWebState) {
activeURL = net::NSURLWithGURL(activeWebState->GetVisibleURL());
}
[self.consumer setURL:activeURL];
}
@end
// Copyright 2020 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.
#ifndef IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_VIEW_CONTROLLER_H_
#import <ScreenTime/ScreenTime.h>
#import "ios/chrome/browser/ui/screen_time/screen_time_consumer.h"
// The view controller which is used to integrate ScreenTime support. This
// object is used to report web usage and block restricted webpages. To properly
// report web usage, add this view controller's view above the web view,
// entirely covering the frame of the web view. This view will automatically
// block when the underlying web view's URL becomes restricted.
API_AVAILABLE(ios(14.0))
@interface ScreenTimeViewController : STWebpageController <ScreenTimeConsumer>
@end
#endif // IOS_CHROME_BROWSER_UI_SCREEN_TIME_SCREEN_TIME_VIEW_CONTROLLER_H_
// Copyright 2020 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/browser/ui/screen_time/screen_time_view_controller.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation ScreenTimeViewController
// The ScreenTimeConsumer implementation comes from the STWebpageController
// parent class.
@end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment