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

Side by Side Diff: ios/chrome/browser/native_app_launcher/native_app_navigation_controller.mm

Issue 2585233003: Upstream Chrome on iOS source code [2/11]. (Closed)
Patch Set: Created 3 years, 12 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "ios/chrome/browser/native_app_launcher/native_app_navigation_controller .h"
6
7 #import <StoreKit/StoreKit.h>
8
9 #include "base/metrics/user_metrics.h"
10 #include "base/metrics/user_metrics_action.h"
11 #include "components/infobars/core/infobar_manager.h"
12 #import "ios/chrome/browser/installation_notifier.h"
13 #include "ios/chrome/browser/native_app_launcher/native_app_infobar_delegate.h"
14 #import "ios/chrome/browser/open_url_util.h"
15 #import "ios/chrome/browser/tabs/tab.h"
16 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
17 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_metad ata.h"
18 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_types .h"
19 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_white list_manager.h"
20 #import "ios/web/navigation/navigation_manager_impl.h"
21 #include "ios/web/public/navigation_item.h"
22 #import "net/base/mac/url_conversions.h"
23 #include "net/url_request/url_request_context_getter.h"
24
25 using base::UserMetricsAction;
26
27 @interface NativeAppNavigationController ()
28 // Shows a native app infobar by looking at the page's URL and by checking
29 // wheter that infobar should be bypassed or not.
30 - (void)showInfoBarIfNecessary;
31
32 // Returns a pointer to the NSMutableSet of |_appsPossiblyBeingInstalled|
33 - (NSMutableSet*)appsPossiblyBeingInstalled;
34
35 // Records what type of infobar was opened.
36 - (void)recordInfobarDisplayedOfType:(NativeAppControllerType)type
37 onLinkNavigation:(BOOL)isLinkNavigation;
38
39 // Returns whether the current state is Link Navigation in the sense of Native
40 // App Launcher, i.e. a navigation caused by an explicit user action in the
41 // rectangle of the web content area.
42 - (BOOL)isLinkNavigation;
43
44 @end
45
46 @implementation NativeAppNavigationController {
47 // A reference to the URLRequestContextGetter needed to fetch icons.
48 scoped_refptr<net::URLRequestContextGetter> _requestContextGetter;
49 // Tab hosting the infobar.
50 __unsafe_unretained Tab* _tab; // weak
51 base::scoped_nsprotocol<id<NativeAppMetadata>> _metadata;
52 // A set of appIds encoded as NSStrings.
53 base::scoped_nsobject<NSMutableSet> _appsPossiblyBeingInstalled;
54 }
55
56 // This prevents incorrect initialization of this object.
57 - (id)init {
58 NOTREACHED();
59 return nil;
60 }
61
62 // Designated initializer. Use this instead of -init.
63 - (id)initWithRequestContextGetter:(net::URLRequestContextGetter*)context
64 tab:(Tab*)tab {
65 self = [super init];
66 if (self) {
67 DCHECK(context);
68 _requestContextGetter = context;
69 // Allows |tab| to be nil for unit testing.
70 _tab = tab;
71 _appsPossiblyBeingInstalled.reset([[NSMutableSet alloc] init]);
72 }
73 return self;
74 }
75
76 - (void)copyStateFrom:(NativeAppNavigationController*)controller {
77 DCHECK(controller);
78 _appsPossiblyBeingInstalled.reset([[NSMutableSet alloc]
79 initWithSet:[controller appsPossiblyBeingInstalled]]);
80 for (NSString* appIdString in _appsPossiblyBeingInstalled.get()) {
81 DCHECK([appIdString isKindOfClass:[NSString class]]);
82 NSURL* appURL =
83 [ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()
84 schemeForAppId:appIdString];
85 [[InstallationNotifier sharedInstance]
86 registerForInstallationNotifications:self
87 withSelector:@selector(appDidInstall:)
88 forScheme:[appURL scheme]];
89 }
90 [self showInfoBarIfNecessary];
91 }
92
93 - (void)dealloc {
94 [[InstallationNotifier sharedInstance] unregisterForNotifications:self];
95 [super dealloc];
96 }
97
98 - (NSMutableSet*)appsPossiblyBeingInstalled {
99 return _appsPossiblyBeingInstalled;
100 }
101
102 - (void)showInfoBarIfNecessary {
103 // Find a potential matching native app.
104 GURL pageURL = _tab.webState->GetLastCommittedURL();
105 _metadata.reset(
106 [ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()
107 newNativeAppForURL:pageURL]);
108 if (!_metadata || [_metadata shouldBypassInfoBars])
109 return;
110
111 // Select the infobar type.
112 NativeAppControllerType type;
113 if ([_metadata canOpenURL:pageURL]) { // App is installed.
114 type = [self isLinkNavigation] && ![_metadata shouldAutoOpenLinks]
115 ? NATIVE_APP_OPEN_POLICY_CONTROLLER
116 : NATIVE_APP_LAUNCHER_CONTROLLER;
117 } else { // App is not installed.
118 // Check if the user already opened the store for this app.
119 if ([_appsPossiblyBeingInstalled containsObject:[_metadata appId]])
120 return;
121 type = NATIVE_APP_INSTALLER_CONTROLLER;
122 }
123 // Inform the metadata that an infobar of |type| will be shown so that metrics
124 // and ignored behavior can be handled.
125 [_metadata willBeShownInInfobarOfType:type];
126 // Display the proper infobar.
127 infobars::InfoBarManager* infoBarManager = [_tab infoBarManager];
128 NativeAppInfoBarDelegate::Create(infoBarManager, self, pageURL, type);
129 [self recordInfobarDisplayedOfType:type
130 onLinkNavigation:[self isLinkNavigation]];
131 }
132
133 - (void)recordInfobarDisplayedOfType:(NativeAppControllerType)type
134 onLinkNavigation:(BOOL)isLinkNavigation {
135 switch (type) {
136 case NATIVE_APP_INSTALLER_CONTROLLER:
137 base::RecordAction(
138 isLinkNavigation
139 ? UserMetricsAction("MobileGALInstallInfoBarLinkNavigation")
140 : UserMetricsAction("MobileGALInstallInfoBarDirectNavigation"));
141 break;
142 case NATIVE_APP_LAUNCHER_CONTROLLER:
143 base::RecordAction(UserMetricsAction("MobileGALLaunchInfoBar"));
144 break;
145 case NATIVE_APP_OPEN_POLICY_CONTROLLER:
146 base::RecordAction(UserMetricsAction("MobileGALOpenPolicyInfoBar"));
147 break;
148 default:
149 NOTREACHED();
150 break;
151 }
152 }
153
154 #pragma mark -
155 #pragma mark NativeAppNavigationControllerProtocol methods
156
157 - (NSString*)appId {
158 return [_metadata appId];
159 }
160
161 - (NSString*)appName {
162 return [_metadata appName];
163 }
164
165 - (void)fetchSmallIconWithCompletionBlock:(void (^)(UIImage*))block {
166 [_metadata fetchSmallIconWithContext:_requestContextGetter.get()
167 completionBlock:block];
168 }
169
170 - (void)openStore {
171 // Register to get a notification when the app is installed.
172 [[InstallationNotifier sharedInstance]
173 registerForInstallationNotifications:self
174 withSelector:@selector(appDidInstall:)
175 forScheme:[_metadata anyScheme]];
176 NSString* appIdString = [self appId];
177 // Defensively early return if native app metadata returns an nil string for
178 // appId which can cause subsequent -addObject: to throw exceptions.
179 if (![appIdString length])
180 return;
181 DCHECK(![_appsPossiblyBeingInstalled containsObject:appIdString]);
182 [_appsPossiblyBeingInstalled addObject:appIdString];
183 [_tab openAppStore:appIdString];
184 }
185
186 - (void)launchApp:(const GURL&)URL {
187 // TODO(crbug.com/353957): Pass the ChromeIdentity to
188 // -launchURLWithURL:identity:
189 GURL launchURL([_metadata launchURLWithURL:URL identity:nil]);
190 if (launchURL.is_valid()) {
191 OpenUrlWithCompletionHandler(net::NSURLWithGURL(launchURL), nil);
192 }
193 }
194
195 - (void)updateMetadataWithUserAction:(NativeAppActionType)userAction {
196 [_metadata updateWithUserAction:userAction];
197 }
198
199 #pragma mark -
200 #pragma mark CRWWebControllerObserver methods
201
202 - (void)pageLoaded:(CRWWebController*)webController {
203 if (![_tab isPrerenderTab])
204 [self showInfoBarIfNecessary];
205 }
206
207 - (void)webControllerWillClose:(CRWWebController*)webController {
208 [webController removeObserver:self];
209 }
210
211 - (BOOL)isLinkNavigation {
212 if (![_tab navigationManager])
213 return NO;
214 web::NavigationItem* userItem = [_tab navigationManager]->GetLastUserItem();
215 if (!userItem)
216 return NO;
217 ui::PageTransition currentTransition = userItem->GetTransitionType();
218 return PageTransitionCoreTypeIs(currentTransition,
219 ui::PAGE_TRANSITION_LINK) ||
220 PageTransitionCoreTypeIs(currentTransition,
221 ui::PAGE_TRANSITION_AUTO_BOOKMARK);
222 }
223
224 - (void)appDidInstall:(NSNotification*)notification {
225 [self removeAppFromNotification:notification];
226 [self showInfoBarIfNecessary];
227 }
228
229 - (void)removeAppFromNotification:(NSNotification*)notification {
230 DCHECK([[notification object] isKindOfClass:[InstallationNotifier class]]);
231 NSString* schemeOfInstalledApp = [notification name];
232 __block NSString* appIDToRemove = nil;
233 [_appsPossiblyBeingInstalled
234 enumerateObjectsUsingBlock:^(id appID, BOOL* stop) {
235 NSURL* appURL =
236 [ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()
237 schemeForAppId:appID];
238 if ([[appURL scheme] isEqualToString:schemeOfInstalledApp]) {
239 appIDToRemove = appID;
240 *stop = YES;
241 }
242 }];
243 DCHECK(appIDToRemove);
244 [_appsPossiblyBeingInstalled removeObject:appIDToRemove];
245 }
246
247 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698