Commit 7a90fb2e authored by Julian Mentasti-Meza's avatar Julian Mentasti-Meza Committed by Commit Bot

[iOS] Single screen screenshot metric action.

Creation of the 'MobileSingleScreenScreenshot' metric and its collection when a user takes a screenshot of a single screen.

Change-Id: Ib95e031a36f922450f602e6fdfb7ccf14928cf76
Bug: 1065909
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2218552Reviewed-by: default avatarRobert Kaplow <rkaplow@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Reviewed-by: default avatarSebastien Lalancette <seblalancette@chromium.org>
Commit-Queue: Julian Mentasti-Meza <jmentasti@google.com>
Cr-Commit-Position: refs/heads/master@{#780918}
parent de7de382
......@@ -207,6 +207,7 @@ source_set("app_internal") {
"//ios/chrome/browser/omaha",
"//ios/chrome/browser/passwords",
"//ios/chrome/browser/reading_list",
"//ios/chrome/browser/screenshot",
"//ios/chrome/browser/search_engines",
"//ios/chrome/browser/search_engines:extension_search_engine_data_updater",
"//ios/chrome/browser/share_extension",
......
......@@ -70,6 +70,7 @@
#include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
#import "ios/chrome/browser/omaha/omaha_service.h"
#include "ios/chrome/browser/pref_names.h"
#include "ios/chrome/browser/screenshot/screenshot_notification_listener.h"
#import "ios/chrome/browser/search_engines/extension_search_engine_data_updater.h"
#include "ios/chrome/browser/search_engines/search_engines_util.h"
#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
......@@ -265,6 +266,10 @@ void MainControllerAuthenticationServiceDelegate::ClearBrowsingData(
// The ChromeBrowserState associated with the main (non-OTR) browsing mode.
@property(nonatomic, assign) ChromeBrowserState* mainBrowserState; // Weak.
// Handles colleting metrics on user triggered screenshots
@property(nonatomic, strong)
ScreenshotNotificationListener* screenshotNotificationListener;
// Returns whether the restore infobar should be displayed.
- (bool)mustShowRestoreInfobar;
// Returns the set of the sessions ids of the tabs in the given |webStateList|.
......@@ -560,6 +565,10 @@ void MainControllerAuthenticationServiceDelegate::ClearBrowsingData(
// Now that everything is properly set up, run the tests.
tests_hook::RunTestsIfPresent();
self.screenshotNotificationListener =
[[ScreenshotNotificationListener alloc] init];
[self.screenshotNotificationListener startListening];
}
- (void)startUpBrowserForegroundInitialization {
......
# 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.
source_set("screenshot") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"screenshot_notification_listener.h",
"screenshot_notification_listener.mm",
]
deps = [ "//base" ]
}
source_set("unit_tests") {
configs += [ "//build/config/compiler:enable_arc" ]
testonly = true
sources = [ "screenshot_notification_listener_unittest.mm" ]
deps = [
"//base",
"//base/test:test_support",
"//ios/chrome/browser/screenshot",
"//ios/chrome/test:test_support",
"//third_party/ocmock",
]
}
// 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 <Foundation/Foundation.h>
#ifndef IOS_CHROME_BROWSER_SCREENSHOT_SCREENSHOT_NOTIFICATION_LISTENER_H_
#define IOS_CHROME_BROWSER_SCREENSHOT_SCREENSHOT_NOTIFICATION_LISTENER_H_
// ScreenshotNotificationListener presents the public interface for
// the screenshot metric collection.
@interface ScreenshotNotificationListener : NSObject
// Adds an observer to the NSNotification centre, and listens for
// the UIApplicationUserDidTakeScreenshotNotification to trigger
// metric collection.
- (void)startListening;
@end
#endif // IOS_CHROME_BROWSER_SCREENSHOT_SCREENSHOT_NOTIFICATION_LISTENER_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/screenshot/screenshot_notification_listener.h"
#import <UIKit/UIKit.h>
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
char const* singleScreenUserActionName = "MobileSingleScreenScreenshot";
} // namespace
@implementation ScreenshotNotificationListener
#pragma mark - Public
- (void)startListening {
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(collectMetricFromNotification:)
name:@"UIApplicationUserDidTakeScreenshotNotification"
object:nil];
}
#pragma mark - Private
/**
* If the device does not support multiple scenes or if the iOS version is
* bellow iOS13 it will record the SingleScreenUserActionName metric.
*
* Otherwise it will record the SingleScreenUserActionName metric only if there
* is a single window in the foreground.
*/
- (void)collectMetricFromNotification:(NSNotification*)notification {
UIApplication* sharedApplication = [UIApplication sharedApplication];
if (@available(iOS 13, *)) {
if (!sharedApplication.supportsMultipleScenes) {
// Multi-Window is not supported, thus there is only a single screen
base::RecordAction(base::UserMetricsAction(singleScreenUserActionName));
return;
}
// Inspect the connectScenes and map the current window scenario
NSInteger foreground = 0;
// NSLog(@"I got the following: %@", [sharedApplication connectedScenes]);
for (UIScene* scene in [sharedApplication connectedScenes]) {
switch (scene.activationState) {
case UISceneActivationStateForegroundActive:
foreground++;
break;
case UISceneActivationStateForegroundInactive:
foreground++;
break;
default:
// Catch for UISceneActivationStateUnattached
// and UISceneActivationStateBackground
// TODO (crbug.com/1091818): Add state inpection to identify other
// scenarios
break;
}
}
// Only register screenshots taken of chrome in a single screen in the
// foreground.
if (foreground == 1) {
base::RecordAction(base::UserMetricsAction(singleScreenUserActionName));
}
return;
}
// If we reach this line, then it means the iOS < 13 thus there is only a
// single window
base::RecordAction(base::UserMetricsAction(singleScreenUserActionName));
}
@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.
#import "ios/chrome/browser/screenshot/screenshot_notification_listener.h"
#import <UIKit/UIKit.h>
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/test/metrics/user_action_tester.h"
#include "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
char const* singleScreenUserActionName = "MobileSingleScreenScreenshot";
} // namespace
class ScreenshotNotificationListenerTest : public PlatformTest {
protected:
ScreenshotNotificationListenerTest() {}
~ScreenshotNotificationListenerTest() override {}
void SetUp() override {
sharedMock_ = OCMPartialMock([UIApplication sharedApplication]);
screenshotNotificationListener_ =
[[ScreenshotNotificationListener alloc] init];
[screenshotNotificationListener_ startListening];
if (@available(iOS 13, *))
windowSceneMock_ = OCMClassMock([UIWindowScene class]);
}
void SendScreenshotNotification() {
[NSNotificationCenter.defaultCenter
postNotificationName:@"UIApplicationUserDidTakeScreenshotNotification"
object:nil
userInfo:nil];
}
id sharedMock_;
id windowSceneMock_;
base::UserActionTester user_action_tester_;
ScreenshotNotificationListener* screenshotNotificationListener_;
};
// Tests when a UIApplicationUserDidTakeScreenshotNotification
// happens on a device with an iOS less than 13
TEST_F(ScreenshotNotificationListenerTest, iOS12Screenshot) {
// Expected: Metric recorded
if (@available(iOS 13, *))
// If iOS13 test will automatically pass
return
SendScreenshotNotification();
EXPECT_EQ(1, user_action_tester_.GetActionCount(singleScreenUserActionName));
}
// Tests when a UIApplicationUserDidTakeScreenshotNotification
// happens on a device where multiple windows are not enabled.
TEST_F(ScreenshotNotificationListenerTest, iOS13MultiWindowNotEnabled) {
// Expected: Metric recorded
if (@available(iOS 13, *)) {
OCMStub([sharedMock_ supportsMultipleScenes]).andReturn(NO);
SendScreenshotNotification();
EXPECT_EQ(1,
user_action_tester_.GetActionCount(singleScreenUserActionName));
}
}
// Tests that a metric is logged if there's a single screen with a single window
// and a UIApplicationUserDidTakeScreenshotNotification is sent.
TEST_F(ScreenshotNotificationListenerTest, iOS13SingleScreenSingleWindow) {
// Expected: Metric recorded
if (@available(iOS 13, *)) {
OCMStub([sharedMock_ supportsMultipleScenes]).andReturn(YES);
id windowSceneMock_ = OCMClassMock([UIWindowScene class]);
// Mark the window as foregroundActive
OCMStub([windowSceneMock_ activationState])
.andReturn(UISceneActivationStateForegroundActive);
NSSet* sceneSet = [NSSet setWithObject:windowSceneMock_];
// Attatch it to the sharedApplication
OCMStub([sharedMock_ connectedScenes]).andReturn(sceneSet);
SendScreenshotNotification();
EXPECT_EQ(1,
user_action_tester_.GetActionCount(singleScreenUserActionName));
}
}
// Tests that a metric is logged if there're are multiple screens each with
// a single window and a UIApplicationUserDidTakeScreenshotNotification is
// sent.
TEST_F(ScreenshotNotificationListenerTest, iOS13MultiScreenSingleWindow) {
// Expected: Metric recorded
if (@available(iOS 13, *)) {
OCMStub([sharedMock_ supportsMultipleScenes]).andReturn(YES);
// Mark the window as foregroundActive
id foregroundWindowSceneMock = OCMClassMock([UIWindowScene class]);
OCMStub([windowSceneMock_ activationState])
.andReturn(UISceneActivationStateForegroundActive);
// Mark the window as Background
id backgroundWindowSceneMock = OCMClassMock([UIWindowScene class]);
OCMStub([backgroundWindowSceneMock activationState])
.andReturn(UISceneActivationStateBackground);
NSSet* sceneSet =
[[NSSet alloc] initWithObjects:foregroundWindowSceneMock,
backgroundWindowSceneMock, nil];
// Attatch the Scene State to the sharedApplication
OCMStub([sharedMock_ connectedScenes]).andReturn(sceneSet);
SendScreenshotNotification();
EXPECT_EQ(1,
user_action_tester_.GetActionCount(singleScreenUserActionName));
}
}
// Tests that a metric is not logged if there is a multi-window screen in the
// foreground and a UIApplicationUserDidTakeScreenshotNotification is sent.
TEST_F(ScreenshotNotificationListenerTest, iOS13MultiScreenMultiWindow) {
// Expected: Metric not recorded
if (@available(iOS 13, *)) {
OCMStub([sharedMock_ supportsMultipleScenes]).andReturn(YES);
// Mark the window as foregroundActive
id firstForegroundWindowSceneMock = OCMClassMock([UIWindowScene class]);
OCMStub([windowSceneMock_ activationState])
.andReturn(UISceneActivationStateForegroundActive);
// Mark the window as foregroundActive
id secondForegroundWindowSceneMock = OCMClassMock([UIWindowScene class]);
OCMStub([secondForegroundWindowSceneMock activationState])
.andReturn(UISceneActivationStateForegroundActive);
NSSet* sceneSet =
[[NSSet alloc] initWithObjects:firstForegroundWindowSceneMock,
secondForegroundWindowSceneMock, nil];
// Attatch the Scene State to the sharedApplication
OCMStub([sharedMock_ connectedScenes]).andReturn(sceneSet);
SendScreenshotNotification();
EXPECT_EQ(0,
user_action_tester_.GetActionCount(singleScreenUserActionName));
}
}
......@@ -228,6 +228,7 @@ test("ios_chrome_unittests") {
"//ios/chrome/browser/reading_list:unit_tests",
"//ios/chrome/browser/safe_browsing:unit_tests",
"//ios/chrome/browser/safe_mode:unit_tests",
"//ios/chrome/browser/screenshot:unit_tests",
"//ios/chrome/browser/search_engines:unit_tests",
"//ios/chrome/browser/send_tab_to_self:unit_tests",
"//ios/chrome/browser/sessions:unit_tests",
......
......@@ -14291,6 +14291,14 @@ should be able to be added at any place in this file.
<description>Please enter the description of this user action.</description>
</action>
<action name="MobileSingleScreenScreenshot">
<owner>jmentasti@google.com</owner>
<owner>seblalancette@chromium.org</owner>
<description>
The user took a screenshot of a single chrome window. iOS Only.
</description>
</action>
<action name="MobileStackViewCloseTab">
<owner>Please list the metric's owners. Add more owner tags as needed.</owner>
<description>Please enter the description of this user action.</description>
......
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