OLD | NEW |
| (Empty) |
1 // Copyright 2017 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/widget_extension/widget_view_controller.h" | |
6 | |
7 #import <NotificationCenter/NotificationCenter.h> | |
8 | |
9 #include "base/ios/ios_util.h" | |
10 #include "base/mac/foundation_util.h" | |
11 #include "base/strings/sys_string_conversions.h" | |
12 #include "components/open_from_clipboard/clipboard_recent_content_impl_ios.h" | |
13 #include "ios/chrome/common/app_group/app_group_constants.h" | |
14 #import "ios/chrome/widget_extension/widget_view.h" | |
15 | |
16 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
17 #error "This file requires ARC support." | |
18 #endif | |
19 | |
20 namespace { | |
21 // Using GURL in the extension is not wanted as it includes ICU which makes the | |
22 // extension binary much larger; therefore, ios/chrome/common/x_callback_url.h | |
23 // cannot be used. This class makes a very basic use of x-callback-url, so no | |
24 // full implementation is required. | |
25 NSString* const kXCallbackURLHost = @"x-callback-url"; | |
26 } // namespace | |
27 | |
28 @interface WidgetViewController ()<WidgetViewActionTarget> | |
29 @property(nonatomic, weak) WidgetView* widgetView; | |
30 @property(nonatomic, strong) NSURL* copiedURL; | |
31 @property(nonatomic, strong) | |
32 ClipboardRecentContentImplIOS* clipboardRecentContent; | |
33 | |
34 // Updates the widget with latest data from the clipboard. Returns whether any | |
35 // visual updates occured. | |
36 - (BOOL)updateWidget; | |
37 // Opens the main application with the given |command|. | |
38 - (void)openAppWithCommand:(NSString*)command; | |
39 // Opens the main application with the given |command| and |parameter|. | |
40 - (void)openAppWithCommand:(NSString*)command parameter:(NSString*)parameter; | |
41 // Returns the dictionary of commands to pass via user defaults to open the main | |
42 // application for a given |command| and |parameter|. | |
43 + (NSDictionary*)dictForCommand:(NSString*)command | |
44 parameter:(NSString*)parameter; | |
45 | |
46 @end | |
47 | |
48 @implementation WidgetViewController | |
49 | |
50 @synthesize widgetView = _widgetView; | |
51 @synthesize copiedURL = _copiedURL; | |
52 @synthesize clipboardRecentContent = _clipboardRecentContent; | |
53 | |
54 - (instancetype)init { | |
55 self = [super init]; | |
56 if (self) { | |
57 _clipboardRecentContent = [[ClipboardRecentContentImplIOS alloc] | |
58 initWithMaxAge:1 * 60 * 60 | |
59 authorizedSchemes:[NSSet setWithObjects:@"http", @"https", nil] | |
60 userDefaults:app_group::GetGroupUserDefaults() | |
61 delegate:nil]; | |
62 } | |
63 return self; | |
64 } | |
65 | |
66 #pragma mark - UIViewController | |
67 | |
68 - (void)viewDidLoad { | |
69 [super viewDidLoad]; | |
70 | |
71 // A local variable is necessary here as the property is declared weak and the | |
72 // object would be deallocated before being retained by the addSubview call. | |
73 WidgetView* widgetView = [[WidgetView alloc] initWithActionTarget:self]; | |
74 self.widgetView = widgetView; | |
75 [self.view addSubview:self.widgetView]; | |
76 | |
77 if (base::ios::IsRunningOnIOS10OrLater()) { | |
78 self.extensionContext.widgetLargestAvailableDisplayMode = | |
79 NCWidgetDisplayModeExpanded; | |
80 } | |
81 | |
82 self.widgetView.translatesAutoresizingMaskIntoConstraints = NO; | |
83 | |
84 NSLayoutConstraint* heightAnchor = [self.widgetView.heightAnchor | |
85 constraintEqualToAnchor:self.view.heightAnchor]; | |
86 heightAnchor.priority = 900; | |
87 | |
88 [NSLayoutConstraint activateConstraints:@[ | |
89 [self.widgetView.leadingAnchor | |
90 constraintEqualToAnchor:self.view.leadingAnchor], | |
91 [self.widgetView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], | |
92 [self.widgetView.trailingAnchor | |
93 constraintEqualToAnchor:self.view.trailingAnchor], | |
94 heightAnchor, | |
95 [self.widgetView.topAnchor constraintEqualToAnchor:self.view.topAnchor], | |
96 ]]; | |
97 } | |
98 | |
99 - (void)viewWillAppear:(BOOL)animated { | |
100 [super viewWillAppear:animated]; | |
101 [self updateWidget]; | |
102 } | |
103 | |
104 - (void)widgetPerformUpdateWithCompletionHandler: | |
105 (void (^)(NCUpdateResult))completionHandler { | |
106 completionHandler([self updateWidget] ? NCUpdateResultNewData | |
107 : NCUpdateResultNoData); | |
108 } | |
109 | |
110 - (BOOL)updateWidget { | |
111 NSURL* url = [_clipboardRecentContent recentURLFromClipboard]; | |
112 | |
113 if (![url isEqual:self.copiedURL]) { | |
114 self.copiedURL = url; | |
115 [self.widgetView updateCopiedURL:self.copiedURL.absoluteString]; | |
116 return YES; | |
117 } | |
118 return NO; | |
119 } | |
120 | |
121 #pragma mark - NCWidgetProviding | |
122 | |
123 - (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode | |
124 withMaximumSize:(CGSize)maxSize { | |
125 CGSize fittingSize = [self.widgetView | |
126 systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; | |
127 if (fittingSize.height > maxSize.height) { | |
128 self.preferredContentSize = maxSize; | |
129 } else { | |
130 self.preferredContentSize = fittingSize; | |
131 } | |
132 } | |
133 | |
134 #pragma mark - WidgetViewActionTarget | |
135 | |
136 - (void)openSearch:(id)sender { | |
137 [self openAppWithCommand:base::SysUTF8ToNSString( | |
138 app_group::kChromeAppGroupFocusOmniboxCommand)]; | |
139 } | |
140 | |
141 - (void)openIncognito:(id)sender { | |
142 [self | |
143 openAppWithCommand:base::SysUTF8ToNSString( | |
144 app_group::kChromeAppGroupIncognitoSearchCommand)]; | |
145 } | |
146 | |
147 - (void)openVoice:(id)sender { | |
148 [self openAppWithCommand:base::SysUTF8ToNSString( | |
149 app_group::kChromeAppGroupVoiceSearchCommand)]; | |
150 } | |
151 | |
152 - (void)openQRCode:(id)sender { | |
153 [self openAppWithCommand:base::SysUTF8ToNSString( | |
154 app_group::kChromeAppGroupQRScannerCommand)]; | |
155 } | |
156 | |
157 - (void)openCopiedURL:(id)sender { | |
158 DCHECK(self.copiedURL); | |
159 [self openAppWithCommand:base::SysUTF8ToNSString( | |
160 app_group::kChromeAppGroupOpenURLCommand) | |
161 parameter:self.copiedURL.absoluteString]; | |
162 } | |
163 | |
164 #pragma mark - internal | |
165 | |
166 - (void)openAppWithCommand:(NSString*)command { | |
167 return [self openAppWithCommand:command parameter:nil]; | |
168 } | |
169 | |
170 - (void)openAppWithCommand:(NSString*)command parameter:(NSString*)parameter { | |
171 NSUserDefaults* sharedDefaults = | |
172 [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()]; | |
173 NSString* defaultsKey = | |
174 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference); | |
175 [sharedDefaults setObject:[WidgetViewController dictForCommand:command | |
176 parameter:parameter] | |
177 forKey:defaultsKey]; | |
178 [sharedDefaults synchronize]; | |
179 | |
180 NSString* scheme = base::mac::ObjCCast<NSString>([[NSBundle mainBundle] | |
181 objectForInfoDictionaryKey:@"KSChannelChromeScheme"]); | |
182 if (!scheme) | |
183 return; | |
184 | |
185 NSURLComponents* urlComponents = [NSURLComponents new]; | |
186 urlComponents.scheme = scheme; | |
187 urlComponents.host = kXCallbackURLHost; | |
188 urlComponents.path = [NSString | |
189 stringWithFormat:@"/%@", base::SysUTF8ToNSString( | |
190 app_group::kChromeAppGroupXCallbackCommand)]; | |
191 | |
192 NSURL* openURL = [urlComponents URL]; | |
193 [self.extensionContext openURL:openURL completionHandler:nil]; | |
194 } | |
195 | |
196 + (NSDictionary*)dictForCommand:(NSString*)command | |
197 parameter:(NSString*)parameter { | |
198 NSString* timePrefKey = | |
199 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference); | |
200 NSString* appPrefKey = | |
201 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference); | |
202 NSString* commandPrefKey = base::SysUTF8ToNSString( | |
203 app_group::kChromeAppGroupCommandCommandPreference); | |
204 | |
205 if (parameter) { | |
206 NSString* paramPrefKey = base::SysUTF8ToNSString( | |
207 app_group::kChromeAppGroupCommandParameterPreference); | |
208 return @{ | |
209 timePrefKey : [NSDate date], | |
210 appPrefKey : @"TodayExtension", | |
211 commandPrefKey : command, | |
212 paramPrefKey : parameter, | |
213 }; | |
214 } | |
215 return @{ | |
216 timePrefKey : [NSDate date], | |
217 appPrefKey : @"TodayExtension", | |
218 commandPrefKey : command, | |
219 }; | |
220 } | |
221 | |
222 @end | |
OLD | NEW |