OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/widget_extension/widget_view_controller.h" | 5 #import "ios/chrome/widget_extension/widget_view_controller.h" |
6 | 6 |
7 #import <NotificationCenter/NotificationCenter.h> | 7 #import <NotificationCenter/NotificationCenter.h> |
8 | 8 |
9 #include "base/ios/ios_util.h" | |
9 #include "base/mac/foundation_util.h" | 10 #include "base/mac/foundation_util.h" |
10 #include "base/strings/sys_string_conversions.h" | 11 #include "base/strings/sys_string_conversions.h" |
12 #include "components/open_from_clipboard/clipboard_recent_content_impl_ios.h" | |
11 #include "ios/chrome/common/app_group/app_group_constants.h" | 13 #include "ios/chrome/common/app_group/app_group_constants.h" |
12 #include "ios/chrome/common/x_callback_url.h" | |
13 #import "ios/chrome/widget_extension/widget_view.h" | 14 #import "ios/chrome/widget_extension/widget_view.h" |
14 #import "net/base/mac/url_conversions.h" | |
15 #include "url/gurl.h" | |
16 | 15 |
17 #if !defined(__has_feature) || !__has_feature(objc_arc) | 16 #if !defined(__has_feature) || !__has_feature(objc_arc) |
18 #error "This file requires ARC support." | 17 #error "This file requires ARC support." |
19 #endif | 18 #endif |
20 | 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 | |
21 @interface WidgetViewController ()<WidgetViewActionTarget> | 28 @interface WidgetViewController ()<WidgetViewActionTarget> |
22 @property(nonatomic, weak) WidgetView* widgetView; | 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 | |
23 @end | 46 @end |
24 | 47 |
25 @implementation WidgetViewController | 48 @implementation WidgetViewController |
26 | 49 |
27 @synthesize widgetView = _widgetView; | 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 initWithAuthorizedSchemes:[NSSet setWithObjects:@"http", @"https", nil] | |
59 userDefaults:app_group::GetGroupUserDefaults() | |
60 delegate:nil]; | |
61 } | |
62 return self; | |
63 } | |
28 | 64 |
29 #pragma mark - UIViewController | 65 #pragma mark - UIViewController |
30 | 66 |
31 - (void)viewDidLoad { | 67 - (void)viewDidLoad { |
32 [super viewDidLoad]; | 68 [super viewDidLoad]; |
33 | 69 |
34 // A local variable is necessary here as the property is declared weak and the | 70 // A local variable is necessary here as the property is declared weak and the |
35 // object would be deallocated before being retained by the addSubview call. | 71 // object would be deallocated before being retained by the addSubview call. |
36 WidgetView* widgetView = [[WidgetView alloc] initWithActionTarget:self]; | 72 WidgetView* widgetView = [[WidgetView alloc] initWithActionTarget:self]; |
37 self.widgetView = widgetView; | 73 self.widgetView = widgetView; |
38 [self.view addSubview:self.widgetView]; | 74 [self.view addSubview:self.widgetView]; |
75 [self updateWidget]; | |
lpromero
2017/04/11 15:05:29
Is this still needed here given that you will call
lody
2017/04/13 11:39:50
Done.
| |
39 | 76 |
40 [self.widgetView setTranslatesAutoresizingMaskIntoConstraints:NO]; | 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 | |
41 [NSLayoutConstraint activateConstraints:@[ | 88 [NSLayoutConstraint activateConstraints:@[ |
42 [self.widgetView.leadingAnchor | 89 [self.widgetView.leadingAnchor |
43 constraintEqualToAnchor:[self.view leadingAnchor]], | 90 constraintEqualToAnchor:self.view.leadingAnchor], |
91 [self.widgetView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], | |
44 [self.widgetView.trailingAnchor | 92 [self.widgetView.trailingAnchor |
45 constraintEqualToAnchor:[self.view trailingAnchor]], | 93 constraintEqualToAnchor:self.view.trailingAnchor], |
46 [self.widgetView.heightAnchor | 94 heightAnchor, |
47 constraintEqualToAnchor:[self.view heightAnchor]], | 95 [self.widgetView.topAnchor constraintEqualToAnchor:self.view.topAnchor], |
48 [self.widgetView.widthAnchor | |
49 constraintEqualToAnchor:[self.view widthAnchor]] | |
50 ]]; | 96 ]]; |
51 } | 97 } |
52 | 98 |
53 - (void)openApp:(id)sender { | 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 { | |
54 NSUserDefaults* sharedDefaults = | 171 NSUserDefaults* sharedDefaults = |
55 [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()]; | 172 [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()]; |
56 NSString* defaultsKey = | 173 NSString* defaultsKey = |
57 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference); | 174 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference); |
58 [sharedDefaults setObject:[WidgetViewController commandDict] | 175 [sharedDefaults setObject:[WidgetViewController dictForCommand:command |
176 parameter:parameter] | |
59 forKey:defaultsKey]; | 177 forKey:defaultsKey]; |
60 [sharedDefaults synchronize]; | 178 [sharedDefaults synchronize]; |
61 | 179 |
62 NSString* scheme = base::mac::ObjCCast<NSString>([[NSBundle mainBundle] | 180 NSString* scheme = base::mac::ObjCCast<NSString>([[NSBundle mainBundle] |
63 objectForInfoDictionaryKey:@"KSChannelChromeScheme"]); | 181 objectForInfoDictionaryKey:@"KSChannelChromeScheme"]); |
64 if (!scheme) | 182 if (!scheme) |
65 return; | 183 return; |
66 const GURL openURL = | 184 |
67 CreateXCallbackURL(base::SysNSStringToUTF8(scheme), | 185 NSURLComponents* urlComponents = [NSURLComponents new]; |
68 app_group::kChromeAppGroupXCallbackCommand); | 186 urlComponents.scheme = scheme; |
69 [self.extensionContext openURL:net::NSURLWithGURL(openURL) | 187 urlComponents.host = kXCallbackURLHost; |
70 completionHandler:nil]; | 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]; | |
71 } | 194 } |
72 | 195 |
73 + (NSDictionary*)commandDict { | 196 + (NSDictionary*)dictForCommand:(NSString*)command |
74 NSString* command = | 197 parameter:(NSString*)parameter { |
75 base::SysUTF8ToNSString(app_group::kChromeAppGroupFocusOmniboxCommand); | |
76 NSString* timePrefKey = | 198 NSString* timePrefKey = |
77 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference); | 199 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference); |
78 NSString* appPrefKey = | 200 NSString* appPrefKey = |
79 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference); | 201 base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference); |
80 NSString* commandPrefKey = base::SysUTF8ToNSString( | 202 NSString* commandPrefKey = base::SysUTF8ToNSString( |
81 app_group::kChromeAppGroupCommandCommandPreference); | 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 } | |
82 return @{ | 215 return @{ |
83 timePrefKey : [NSDate date], | 216 timePrefKey : [NSDate date], |
84 appPrefKey : @"TodayExtension", | 217 appPrefKey : @"TodayExtension", |
85 commandPrefKey : command, | 218 commandPrefKey : command, |
86 }; | 219 }; |
87 } | 220 } |
88 | 221 |
89 @end | 222 @end |
OLD | NEW |