Commit b461eca9 authored by Chris Lu's avatar Chris Lu Committed by Commit Bot

[ios] Add Main Intent Action

This change adds a new hasPendingExternalIntent property to SceneState
to track scenes that receive an external intent. It is used in
firstSceneWillEnterForeground: to identify app opens that were not
triggered by an external intent and log a user action for it.

Change-Id: I8925457131c47162b68a9ada1c3deeba9554ee0d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2486395Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Commit-Queue: Chris Lu <thegreenfrog@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825925}
parent 6f981d3d
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/ios/ios_util.h" #include "base/ios/ios_util.h"
#include "base/ios/multi_window_buildflags.h" #include "base/ios/multi_window_buildflags.h"
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
#include "base/metrics/user_metrics.h"
#import "ios/chrome/app/application_delegate/app_state.h" #import "ios/chrome/app/application_delegate/app_state.h"
#import "ios/chrome/app/application_delegate/browser_launcher.h" #import "ios/chrome/app/application_delegate/browser_launcher.h"
#import "ios/chrome/app/application_delegate/memory_warning_helper.h" #import "ios/chrome/app/application_delegate/memory_warning_helper.h"
...@@ -32,6 +33,12 @@ ...@@ -32,6 +33,12 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
namespace {
// The time delay after firstSceneWillEnterForeground: before checking for main
// intent signals.
const int kMainIntentCheckDelay = 1;
} // namespace
@interface MainApplicationDelegate () { @interface MainApplicationDelegate () {
MainController* _mainController; MainController* _mainController;
// Memory helper used to log the number of memory warnings received. // Memory helper used to log the number of memory warnings received.
...@@ -279,6 +286,13 @@ ...@@ -279,6 +286,13 @@
- (void)lastSceneDidEnterBackground:(NSNotification*)notification { - (void)lastSceneDidEnterBackground:(NSNotification*)notification {
DCHECK(IsSceneStartupSupported()); DCHECK(IsSceneStartupSupported());
// Reset |startupHadExternalIntent| for all Scenes in case external intents
// were triggered while the application was in the foreground.
for (SceneState* scene in self.appState.connectedScenes) {
if (scene.startupHadExternalIntent) {
scene.startupHadExternalIntent = NO;
}
}
if (@available(iOS 13, *)) { if (@available(iOS 13, *)) {
[_appState applicationDidEnterBackground:UIApplication.sharedApplication [_appState applicationDidEnterBackground:UIApplication.sharedApplication
memoryHelper:_memoryHelper]; memoryHelper:_memoryHelper];
...@@ -288,9 +302,36 @@ ...@@ -288,9 +302,36 @@
- (void)firstSceneWillEnterForeground:(NSNotification*)notification { - (void)firstSceneWillEnterForeground:(NSNotification*)notification {
DCHECK(IsSceneStartupSupported()); DCHECK(IsSceneStartupSupported());
if (@available(iOS 13, *)) { if (@available(iOS 13, *)) {
[_appState applicationWillEnterForeground:UIApplication.sharedApplication __weak MainApplicationDelegate* weakSelf = self;
metricsMediator:_metricsMediator // Delay Main Intent check since signals for intents like spotlight actions
memoryHelper:_memoryHelper]; // are not guaranteed to occur before firstSceneWillEnterForeground.
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
static_cast<int64_t>(kMainIntentCheckDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
MainApplicationDelegate* strongSelf = weakSelf;
if (!strongSelf) {
return;
}
BOOL appStartupFromExternalIntent = NO;
for (SceneState* scene in strongSelf.appState.connectedScenes) {
if (scene.startupHadExternalIntent) {
appStartupFromExternalIntent = YES;
scene.startupHadExternalIntent = NO;
}
}
if (!appStartupFromExternalIntent) {
base::RecordAction(
base::UserMetricsAction("IOSLaunchedBySearchInChromeIntent"));
}
[_appState
applicationWillEnterForeground:UIApplication.sharedApplication
metricsMediator:_metricsMediator
memoryHelper:_memoryHelper];
});
} }
} }
......
...@@ -511,6 +511,7 @@ const char kMultiWindowOpenInNewWindowHistogram[] = ...@@ -511,6 +511,7 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
- (void)performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem - (void)performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem
completionHandler:(void (^)(BOOL succeeded))completionHandler completionHandler:(void (^)(BOOL succeeded))completionHandler
API_AVAILABLE(ios(13)) { API_AVAILABLE(ios(13)) {
self.sceneState.startupHadExternalIntent = YES;
[UserActivityHandler [UserActivityHandler
performActionForShortcutItem:shortcutItem performActionForShortcutItem:shortcutItem
completionHandler:completionHandler completionHandler:completionHandler
...@@ -531,6 +532,7 @@ const char kMultiWindowOpenInNewWindowHistogram[] = ...@@ -531,6 +532,7 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
self.sceneState.presentingModalOverlay) { self.sceneState.presentingModalOverlay) {
sceneIsActive = NO; sceneIsActive = NO;
} }
self.sceneState.startupHadExternalIntent = YES;
[UserActivityHandler [UserActivityHandler
continueUserActivity:userActivity continueUserActivity:userActivity
applicationIsActive:sceneIsActive applicationIsActive:sceneIsActive
......
...@@ -64,6 +64,9 @@ NSString* const kOriginDetectedKey = @"OriginDetectedKey"; ...@@ -64,6 +64,9 @@ NSString* const kOriginDetectedKey = @"OriginDetectedKey";
options:connectionOptions]; options:connectionOptions];
self.sceneState.activationLevel = SceneActivationLevelBackground; self.sceneState.activationLevel = SceneActivationLevelBackground;
self.sceneState.connectionOptions = connectionOptions; self.sceneState.connectionOptions = connectionOptions;
if (connectionOptions.URLContexts || connectionOptions.shortcutItem) {
self.sceneState.startupHadExternalIntent = YES;
}
} }
- (WindowActivityOrigin)originFromSession:(UISceneSession*)session - (WindowActivityOrigin)originFromSession:(UISceneSession*)session
...@@ -126,6 +129,7 @@ NSString* const kOriginDetectedKey = @"OriginDetectedKey"; ...@@ -126,6 +129,7 @@ NSString* const kOriginDetectedKey = @"OriginDetectedKey";
openURLContexts:(NSSet<UIOpenURLContext*>*)URLContexts openURLContexts:(NSSet<UIOpenURLContext*>*)URLContexts
API_AVAILABLE(ios(13)) { API_AVAILABLE(ios(13)) {
DCHECK(!self.sceneState.URLContextsToOpen); DCHECK(!self.sceneState.URLContextsToOpen);
self.sceneState.startupHadExternalIntent = YES;
self.sceneState.URLContextsToOpen = URLContexts; self.sceneState.URLContextsToOpen = URLContexts;
} }
......
...@@ -89,6 +89,10 @@ typedef NS_ENUM(NSUInteger, SceneActivationLevel) { ...@@ -89,6 +89,10 @@ typedef NS_ENUM(NSUInteger, SceneActivationLevel) {
// When this is YES, the scene is showing the modal overlay. // When this is YES, the scene is showing the modal overlay.
@property(nonatomic, assign) BOOL presentingModalOverlay; @property(nonatomic, assign) BOOL presentingModalOverlay;
// When this is YES, the scene either resumed or started up in response to an
// external intent.
@property(nonatomic, assign) BOOL startupHadExternalIntent;
// URLs passed to |UIWindowSceneDelegate scene:openURLContexts:| that needs to // URLs passed to |UIWindowSceneDelegate scene:openURLContexts:| that needs to
// be open next time the scene is activated. // be open next time the scene is activated.
// Setting the property to not nil will add the new URL contexts to the set. // Setting the property to not nil will add the new URL contexts to the set.
......
...@@ -9271,6 +9271,15 @@ should be able to be added at any place in this file. ...@@ -9271,6 +9271,15 @@ should be able to be added at any place in this file.
</description> </description>
</action> </action>
<action name="IOSOpenByMainIntent">
<owner>thegreenfrog@chromium.org</owner>
<owner>olivierrobin@chromium.org</owner>
<description>
User opened Chrome through a main intent, either by an icon open or an app
switch.
</description>
</action>
<action name="IOSPasswordsSettingsCloseWithSwipe"> <action name="IOSPasswordsSettingsCloseWithSwipe">
<owner>djean@chromium.org</owner> <owner>djean@chromium.org</owner>
<owner>javierrobles@chromium.org</owner> <owner>javierrobles@chromium.org</owner>
......
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