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

Side by Side Diff: ios/chrome/browser/ui/settings/native_apps_collection_view_controller.mm

Issue 2899213002: Removed NativeAppsCollectionViewController and related code. (Closed)
Patch Set: removed StoreKit.framework Created 3 years, 6 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 2015 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/ui/settings/native_apps_collection_view_controller.h "
6 #import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller_p rivate.h"
7
8 #import <StoreKit/StoreKit.h>
9
10 #include "base/logging.h"
11 #import "base/mac/foundation_util.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/metrics/user_metrics.h"
15 #include "base/metrics/user_metrics_action.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "base/threading/sequenced_worker_pool.h"
18 #include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
19 #import "ios/chrome/browser/installation_notifier.h"
20 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrom e.h"
21 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item .h"
22 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
23 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
24 #import "ios/chrome/browser/ui/settings/cells/native_app_item.h"
25 #import "ios/chrome/browser/ui/settings/settings_utils.h"
26 #import "ios/chrome/common/string_util.h"
27 #include "ios/chrome/grit/ios_strings.h"
28 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
29 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_metad ata.h"
30 #import "ios/public/provider/chrome/browser/native_app_launcher/native_app_white list_manager.h"
31 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate rialButtons.h"
32 #include "ios/web/public/web_thread.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "url/gurl.h"
35
36 #if !defined(__has_feature) || !__has_feature(objc_arc)
37 #error "This file requires ARC support."
38 #endif
39
40 const NSInteger kTagShift = 1000;
41
42 namespace {
43
44 typedef NS_ENUM(NSInteger, SectionIdentifier) {
45 SectionIdentifierLearnMore = kSectionIdentifierEnumZero,
46 SectionIdentifierApps,
47 };
48
49 typedef NS_ENUM(NSInteger, ItemType) {
50 ItemTypeApp = kItemTypeEnumZero,
51 ItemTypeLearnMore,
52 };
53
54 } // namespace
55
56 @interface NativeAppsCollectionViewController ()<
57 SKStoreProductViewControllerDelegate> {
58 std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> _imageFetcher;
59 NSArray* _nativeAppsInSettings;
60 BOOL _userDidSomething;
61 }
62
63 // List of the native apps visible in Settings.
64 @property(nonatomic, copy) NSArray* appsInSettings;
65
66 // Delegate for App-Store-related operations.
67 @property(nonatomic, weak) id<StoreKitLauncher> storeKitLauncher;
68
69 // Sets up the list of visible apps based on |nativeAppWhitelistManager|, which
70 // serves as datasource for this controller. Apps from
71 // |nativeAppWhitelistManager| are stored in |_nativeAppsInSettings| and
72 // |-reloadData| is sent to the receiver.
73 - (void)configureWithNativeAppWhiteListManager:
74 (id<NativeAppWhitelistManager>)nativeAppWhitelistManager;
75
76 // Returns a new Native App collection view item for the metadata at |index| in
77 // |_nativeAppsInSettings|.
78 - (CollectionViewItem*)nativeAppItemAtIndex:(NSUInteger)index;
79
80 // Target method for the auto open in app switch.
81 // Called when an auto-open-in-app switch is toggled.
82 - (void)autoOpenInAppChanged:(UISwitch*)switchControl;
83
84 // Called when an Install button is being tapped.
85 - (void)installApp:(UIButton*)button;
86
87 // Called when an app with the registered scheme is opened.
88 - (void)appDidInstall:(NSNotification*)notification;
89
90 // Returns the app at |index| in the list of visible apps.
91 - (id<NativeAppMetadata>)nativeAppAtIndex:(NSUInteger)index;
92
93 // Records a user action in UMA under NativeAppLauncher.Settings.
94 // If this method is not called during the lifetime of the view,
95 // |settings::kNativeAppsActionDidNothing| is recorded in UMA.
96 - (void)recordUserAction:(settings::NativeAppsAction)action;
97
98 @end
99
100 @implementation NativeAppsCollectionViewController
101
102 @synthesize storeKitLauncher = _storeKitLauncher;
103
104 - (id)initWithURLRequestContextGetter:
105 (net::URLRequestContextGetter*)requestContextGetter {
106 self = [super initWithStyle:CollectionViewControllerStyleAppBar];
107 if (self) {
108 _imageFetcher = base::MakeUnique<image_fetcher::IOSImageDataFetcherWrapper>(
109 requestContextGetter, web::WebThread::GetBlockingPool());
110 base::RecordAction(base::UserMetricsAction("MobileGALOpenSettings"));
111 _storeKitLauncher = self;
112
113 [self loadModel];
114 }
115 return self;
116 }
117
118 - (void)dealloc {
119 [[InstallationNotifier sharedInstance] unregisterForNotifications:self];
120 if (!_userDidSomething)
121 [self recordUserAction:settings::kNativeAppsActionDidNothing];
122 }
123
124 #pragma mark - View lifecycle
125
126 - (void)viewDidLoad {
127 self.title = l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SETTINGS);
128 [self configureWithNativeAppWhiteListManager:
129 ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()];
130
131 [super viewDidLoad];
132 }
133
134 - (void)viewWillAppear:(BOOL)animated {
135 [super viewWillAppear:animated];
136 [[InstallationNotifier sharedInstance] checkNow];
137 [[NSNotificationCenter defaultCenter]
138 addObserver:self
139 selector:@selector(reloadData)
140 name:UIApplicationDidBecomeActiveNotification
141 object:nil];
142 }
143
144 - (void)viewDidDisappear:(BOOL)animated {
145 [super viewDidDisappear:animated];
146 [[NSNotificationCenter defaultCenter]
147 removeObserver:self
148 name:UIApplicationDidBecomeActiveNotification
149 object:nil];
150 }
151
152 #pragma mark - CollectionViewController
153
154 - (void)loadModel {
155 [super loadModel];
156 CollectionViewModel* model = self.collectionViewModel;
157 NSUInteger appsCount = [_nativeAppsInSettings count];
158
159 [model addSectionWithIdentifier:SectionIdentifierLearnMore];
160 [model addItem:[self learnMoreItem]
161 toSectionWithIdentifier:SectionIdentifierLearnMore];
162
163 [model addSectionWithIdentifier:SectionIdentifierApps];
164
165 for (NSUInteger i = 0; i < appsCount; i++) {
166 [model addItem:[self nativeAppItemAtIndex:i]
167 toSectionWithIdentifier:SectionIdentifierApps];
168 }
169 }
170
171 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
172 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
173 UICollectionViewCell* cell =
174 [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
175 if ([self.collectionViewModel
176 sectionIdentifierForSection:indexPath.section] ==
177 SectionIdentifierApps) {
178 NativeAppCell* appCell = base::mac::ObjCCastStrict<NativeAppCell>(cell);
179 [self configureNativeAppCell:appCell atIndexPath:indexPath];
180 }
181 return cell;
182 }
183
184 #pragma mark - MDCCollectionViewStylingDelegate
185
186 - (CGFloat)collectionView:(nonnull UICollectionView*)collectionView
187 cellHeightAtIndexPath:(nonnull NSIndexPath*)indexPath {
188 CollectionViewItem* item =
189 [self.collectionViewModel itemAtIndexPath:indexPath];
190 switch (item.type) {
191 case ItemTypeLearnMore:
192 return [MDCCollectionViewCell
193 cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
194 forItem:item];
195 case ItemTypeApp:
196 return MDCCellDefaultOneLineWithAvatarHeight;
197 default:
198 return MDCCellDefaultOneLineHeight;
199 }
200 }
201
202 - (void)configureNativeAppCell:(NativeAppCell*)appCell
203 atIndexPath:(NSIndexPath*)indexPath {
204 appCell.switchControl.tag = [self tagForIndexPath:indexPath];
205 [appCell.switchControl addTarget:self
206 action:@selector(autoOpenInAppChanged:)
207 forControlEvents:UIControlEventValueChanged];
208 appCell.installButton.tag = [self tagForIndexPath:indexPath];
209 [appCell.installButton addTarget:self
210 action:@selector(installApp:)
211 forControlEvents:UIControlEventTouchUpInside];
212 CollectionViewItem* item =
213 [self.collectionViewModel itemAtIndexPath:indexPath];
214 NativeAppItem* appItem = base::mac::ObjCCastStrict<NativeAppItem>(item);
215 if (!appItem.icon) {
216 // Fetch the real icon.
217 __weak NativeAppsCollectionViewController* weakSelf = self;
218 id<NativeAppMetadata> metadata = [self nativeAppAtIndex:indexPath.item];
219 [metadata fetchSmallIconWithImageFetcher:_imageFetcher.get()
220 completionBlock:^(UIImage* image) {
221
222 NativeAppsCollectionViewController* strongSelf =
223 weakSelf;
224 if (!image || !strongSelf)
225 return;
226 appItem.icon = image;
227 [strongSelf.collectionView
228 reloadItemsAtIndexPaths:@[ indexPath ]];
229 }];
230 }
231 }
232
233 - (CollectionViewItem*)learnMoreItem {
234 NSString* learnMoreText =
235 l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SECTION_HEADER);
236 CollectionViewFooterItem* learnMoreItem =
237 [[CollectionViewFooterItem alloc] initWithType:ItemTypeLearnMore];
238 learnMoreItem.text = learnMoreText;
239 return learnMoreItem;
240 }
241
242 #pragma mark - SKStoreProductViewControllerDelegate methods
243
244 - (void)productViewControllerDidFinish:
245 (SKStoreProductViewController*)viewController {
246 [self dismissViewControllerAnimated:YES completion:nil];
247 }
248
249 #pragma mark - StoreKitLauncher methods
250
251 - (void)openAppStore:(NSString*)appId {
252 // Reported crashes show that -openAppStore: had been called with
253 // a nil |appId|, but opening AppStore is meaningful only if the |appId| is
254 // not nil, so be defensive and early return if |appId| is nil.
255 if (![appId length])
256 return;
257 NSDictionary* product =
258 @{SKStoreProductParameterITunesItemIdentifier : appId};
259 SKStoreProductViewController* storeViewController =
260 [[SKStoreProductViewController alloc] init];
261 [storeViewController setDelegate:self];
262 [storeViewController loadProductWithParameters:product completionBlock:nil];
263 [self presentViewController:storeViewController animated:YES completion:nil];
264 }
265
266 #pragma mark - MDCCollectionViewStylingDelegate
267
268 // MDCCollectionViewStylingDelegate protocol is implemented so that cells don't
269 // display ink on touch.
270 - (BOOL)collectionView:(nonnull UICollectionView*)collectionView
271 hidesInkViewAtIndexPath:(nonnull NSIndexPath*)indexPath {
272 return YES;
273 }
274
275 - (MDCCollectionViewCellStyle)collectionView:(UICollectionView*)collectionView
276 cellStyleForSection:(NSInteger)section {
277 NSInteger sectionIdentifier =
278 [self.collectionViewModel sectionIdentifierForSection:section];
279 switch (sectionIdentifier) {
280 case SectionIdentifierLearnMore:
281 // Display the Learn More footer in the default style with no "card" UI
282 // and no section padding.
283 return MDCCollectionViewCellStyleDefault;
284 default:
285 return self.styler.cellStyle;
286 }
287 }
288
289 - (BOOL)collectionView:(UICollectionView*)collectionView
290 shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath {
291 NSInteger sectionIdentifier =
292 [self.collectionViewModel sectionIdentifierForSection:indexPath.section];
293 switch (sectionIdentifier) {
294 case SectionIdentifierLearnMore:
295 // Display the Learn More footer without any background image or
296 // shadowing.
297 return YES;
298 default:
299 return NO;
300 }
301 }
302 #pragma mark - Private methods
303
304 - (void)autoOpenInAppChanged:(UISwitch*)switchControl {
305 NSInteger index = [self indexPathForTag:switchControl.tag].item;
306 id<NativeAppMetadata> metadata = [self nativeAppAtIndex:index];
307 DCHECK([metadata isInstalled]);
308 BOOL autoOpenOn = switchControl.on;
309 metadata.shouldAutoOpenLinks = autoOpenOn;
310 [self recordUserAction:(autoOpenOn
311 ? settings::kNativeAppsActionTurnedAutoOpenOn
312 : settings::kNativeAppsActionTurnedAutoOpenOff)];
313 }
314
315 - (void)installApp:(UIButton*)button {
316 [self recordUserAction:settings::kNativeAppsActionClickedInstall];
317 NSInteger index = [self indexPathForTag:button.tag].item;
318 id<NativeAppMetadata> metadata = [self nativeAppAtIndex:index];
319 DCHECK(![metadata isInstalled]);
320 [metadata updateCounterWithAppInstallation];
321
322 // Register to get a notification when the app is installed.
323 [[InstallationNotifier sharedInstance]
324 registerForInstallationNotifications:self
325 withSelector:@selector(appDidInstall:)
326 forScheme:[metadata anyScheme]];
327 [self.storeKitLauncher openAppStore:[metadata appId]];
328 }
329
330 - (void)appDidInstall:(NSNotification*)notification {
331 // The name of the notification is the scheme of the new app installed.
332 GURL url(base::SysNSStringToUTF8([notification name]) + ":");
333 DCHECK(url.is_valid());
334 NSUInteger matchingAppIndex = [_nativeAppsInSettings
335 indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL* stop) {
336 id<NativeAppMetadata> metadata =
337 static_cast<id<NativeAppMetadata>>(obj);
338 return [metadata canOpenURL:url];
339 }];
340 [[self nativeAppAtIndex:matchingAppIndex] setShouldAutoOpenLinks:YES];
341 [self reloadData];
342 }
343
344 - (void)configureWithNativeAppWhiteListManager:
345 (id<NativeAppWhitelistManager>)nativeAppWhitelistManager {
346 NSArray* allApps = [nativeAppWhitelistManager
347 filteredAppsUsingBlock:^(const id<NativeAppMetadata> app, BOOL* stop) {
348 return [app isGoogleOwnedApp];
349 }];
350 [self setAppsInSettings:allApps];
351 [self reloadData];
352 }
353
354 - (id<NativeAppMetadata>)nativeAppAtIndex:(NSUInteger)index {
355 id<NativeAppMetadata> metadata = [_nativeAppsInSettings objectAtIndex:index];
356 DCHECK([metadata conformsToProtocol:@protocol(NativeAppMetadata)]);
357 return metadata;
358 }
359
360 - (void)recordUserAction:(settings::NativeAppsAction)action {
361 _userDidSomething = YES;
362 UMA_HISTOGRAM_ENUMERATION("NativeAppLauncher.Settings", action,
363 settings::kNativeAppsActionCount);
364 }
365
366 - (CollectionViewItem*)nativeAppItemAtIndex:(NSUInteger)index {
367 id<NativeAppMetadata> metadata = [self nativeAppAtIndex:index];
368 // Determine the state of the cell.
369 NativeAppItemState state;
370 if ([metadata isInstalled]) {
371 state = [metadata shouldAutoOpenLinks] ? NativeAppItemSwitchOn
372 : NativeAppItemSwitchOff;
373 } else {
374 state = NativeAppItemInstall;
375 }
376 NativeAppItem* appItem = [[NativeAppItem alloc] initWithType:ItemTypeApp];
377 appItem.name = [metadata appName];
378 appItem.state = state;
379 return appItem;
380 }
381
382 - (NSArray*)appsInSettings {
383 return _nativeAppsInSettings;
384 }
385
386 - (void)setAppsInSettings:(NSArray*)apps {
387 _nativeAppsInSettings = [apps copy];
388 }
389
390 - (NSInteger)tagForIndexPath:(NSIndexPath*)indexPath {
391 DCHECK(indexPath.section ==
392 [self.collectionViewModel
393 sectionForSectionIdentifier:SectionIdentifierApps]);
394 return indexPath.item + kTagShift;
395 }
396
397 - (NSIndexPath*)indexPathForTag:(NSInteger)shiftedTag {
398 NSInteger unshiftedTag = shiftedTag - kTagShift;
399 return [NSIndexPath
400 indexPathForItem:unshiftedTag
401 inSection:[self.collectionViewModel
402 sectionForSectionIdentifier:SectionIdentifierApps]];
403 }
404
405 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698