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

Side by Side Diff: chrome/browser/chromeos/arc/arc_navigation_throttle.cc

Issue 2441563002: arc: Create intermediate directories in c/b/c/arc (Closed)
Patch Set: Moved the boot notification to notification/ Created 4 years, 2 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 2016 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 #include "chrome/browser/chromeos/arc/arc_navigation_throttle.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "components/arc/arc_bridge_service.h"
14 #include "components/arc/arc_service_manager.h"
15 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
16 #include "components/arc/intent_helper/local_activity_resolver.h"
17 #include "components/arc/intent_helper/page_transition_util.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/navigation_controller.h"
20 #include "content/public/browser/navigation_handle.h"
21 #include "content/public/browser/web_contents.h"
22 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
23 #include "ui/base/page_transition_types.h"
24 #include "url/gurl.h"
25
26 namespace arc {
27
28 namespace {
29
30 constexpr uint32_t kMinVersionForHandleUrl = 2;
31 constexpr uint32_t kMinVersionForRequestUrlHandlerList = 2;
32 constexpr uint32_t kMinVersionForAddPreferredPackage = 7;
33
34 scoped_refptr<ActivityIconLoader> GetIconLoader() {
35 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
36 ArcServiceManager* arc_service_manager = ArcServiceManager::Get();
37 return arc_service_manager ? arc_service_manager->icon_loader() : nullptr;
38 }
39
40 // Compares the host name of the referrer and target URL to decide whether
41 // the navigation needs to be overriden.
42 bool ShouldOverrideUrlLoading(const GURL& previous_url,
43 const GURL& current_url) {
44 // When the navigation is initiated in a web page where sending a referrer
45 // is disabled, |previous_url| can be empty. In this case, we should open
46 // it in the desktop browser.
47 if (!previous_url.is_valid() || previous_url.is_empty())
48 return false;
49
50 // Also check |current_url| just in case.
51 if (!current_url.is_valid() || current_url.is_empty()) {
52 DVLOG(1) << "Unexpected URL: " << current_url << ", opening it in Chrome.";
53 return false;
54 }
55
56 return !net::registry_controlled_domains::SameDomainOrHost(
57 current_url, previous_url,
58 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
59 }
60
61 } // namespace
62
63 ArcNavigationThrottle::ArcNavigationThrottle(
64 content::NavigationHandle* navigation_handle,
65 const ShowIntentPickerCallback& show_intent_picker_cb)
66 : content::NavigationThrottle(navigation_handle),
67 show_intent_picker_callback_(show_intent_picker_cb),
68 previous_user_action_(CloseReason::INVALID),
69 weak_ptr_factory_(this) {}
70
71 ArcNavigationThrottle::~ArcNavigationThrottle() = default;
72
73 content::NavigationThrottle::ThrottleCheckResult
74 ArcNavigationThrottle::WillStartRequest() {
75 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
76 // We must not handle navigations started from the context menu.
77 if (navigation_handle()->WasStartedFromContextMenu())
78 return content::NavigationThrottle::PROCEED;
79 return HandleRequest();
80 }
81
82 content::NavigationThrottle::ThrottleCheckResult
83 ArcNavigationThrottle::WillRedirectRequest() {
84 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
85
86 switch (previous_user_action_) {
87 case CloseReason::ERROR:
88 case CloseReason::DIALOG_DEACTIVATED:
89 // User dismissed the dialog, or some error occurred before. Don't
90 // repeatedly pop up the dialog.
91 return content::NavigationThrottle::PROCEED;
92
93 case CloseReason::ALWAYS_PRESSED:
94 case CloseReason::JUST_ONCE_PRESSED:
95 case CloseReason::PREFERRED_ACTIVITY_FOUND:
96 // Should never get here - if the user selected one of these previously,
97 // Chrome should not see a redirect.
98 NOTREACHED();
99
100 case CloseReason::INVALID:
101 // No picker has previously been popped up for this - continue.
102 break;
103 }
104 return HandleRequest();
105 }
106
107 content::NavigationThrottle::ThrottleCheckResult
108 ArcNavigationThrottle::HandleRequest() {
109 const GURL& url = navigation_handle()->GetURL();
110
111 // Always handle http(s) <form> submissions in Chrome for two reasons: 1) we
112 // don't have a way to send POST data to ARC, and 2) intercepting http(s) form
113 // submissions is not very important because such submissions are usually
114 // done within the same domain. ShouldOverrideUrlLoading() below filters out
115 // such submissions anyway.
116 constexpr bool kAllowFormSubmit = false;
117
118 if (ShouldIgnoreNavigation(navigation_handle()->GetPageTransition(),
119 kAllowFormSubmit))
120 return content::NavigationThrottle::PROCEED;
121
122 const GURL previous_url = navigation_handle()->GetReferrer().url;
123 const GURL current_url = navigation_handle()->GetURL();
124 if (!ShouldOverrideUrlLoading(previous_url, current_url))
125 return content::NavigationThrottle::PROCEED;
126
127 ArcServiceManager* arc_service_manager = ArcServiceManager::Get();
128 DCHECK(arc_service_manager);
129 scoped_refptr<LocalActivityResolver> local_resolver =
130 arc_service_manager->activity_resolver();
131 if (local_resolver->ShouldChromeHandleUrl(url)) {
132 // Allow navigation to proceed if there isn't an android app that handles
133 // the given URL.
134 return content::NavigationThrottle::PROCEED;
135 }
136
137 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
138 "RequestUrlHandlerList", kMinVersionForRequestUrlHandlerList);
139 if (!instance)
140 return content::NavigationThrottle::PROCEED;
141 instance->RequestUrlHandlerList(
142 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived,
143 weak_ptr_factory_.GetWeakPtr()));
144 return content::NavigationThrottle::DEFER;
145 }
146
147 // We received the array of app candidates to handle this URL (even the Chrome
148 // app is included).
149 void ArcNavigationThrottle::OnAppCandidatesReceived(
150 mojo::Array<mojom::IntentHandlerInfoPtr> handlers) {
151 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
152 if (handlers.empty() ||
153 (handlers.size() == 1 && ArcIntentHelperBridge::IsIntentHelperPackage(
154 handlers[0]->package_name))) {
155 // This scenario shouldn't be accesed as ArcNavigationThrottle is created
156 // iff there are ARC apps which can actually handle the given URL.
157 DVLOG(1) << "There are no app candidates for this URL: "
158 << navigation_handle()->GetURL().spec();
159 navigation_handle()->Resume();
160 return;
161 }
162
163 // If one of the apps is marked as preferred, use it right away without
164 // showing the UI.
165 for (size_t i = 0; i < handlers.size(); ++i) {
166 if (!handlers[i]->is_preferred)
167 continue;
168 if (ArcIntentHelperBridge::IsIntentHelperPackage(
169 handlers[i]->package_name)) {
170 // If Chrome browser was selected as the preferred app, we should't
171 // create a throttle.
172 DVLOG(1)
173 << "Chrome browser is selected as the preferred app for this URL: "
174 << navigation_handle()->GetURL().spec();
175 }
176 OnIntentPickerClosed(std::move(handlers), i,
177 CloseReason::PREFERRED_ACTIVITY_FOUND);
178 return;
179 }
180
181 // Swap Chrome app with any app in row |kMaxAppResults-1| iff its index is
182 // bigger, thus ensuring the user can always see Chrome without scrolling.
183 size_t chrome_app_index = 0;
184 for (size_t i = 0; i < handlers.size(); ++i) {
185 if (ArcIntentHelperBridge::IsIntentHelperPackage(
186 handlers[i]->package_name)) {
187 chrome_app_index = i;
188 break;
189 }
190 }
191
192 if (chrome_app_index >= kMaxAppResults)
193 std::swap(handlers[kMaxAppResults - 1], handlers[chrome_app_index]);
194
195 scoped_refptr<ActivityIconLoader> icon_loader = GetIconLoader();
196 if (!icon_loader) {
197 LOG(ERROR) << "Cannot get an instance of ActivityIconLoader";
198 navigation_handle()->Resume();
199 return;
200 }
201 std::vector<ActivityIconLoader::ActivityName> activities;
202 for (const auto& handler : handlers) {
203 activities.emplace_back(handler->package_name, handler->activity_name);
204 }
205 icon_loader->GetActivityIcons(
206 activities,
207 base::Bind(&ArcNavigationThrottle::OnAppIconsReceived,
208 weak_ptr_factory_.GetWeakPtr(), base::Passed(&handlers)));
209 }
210
211 void ArcNavigationThrottle::OnAppIconsReceived(
212 mojo::Array<mojom::IntentHandlerInfoPtr> handlers,
213 std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> icons) {
214 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
215 std::vector<NameAndIcon> app_info;
216
217 for (const auto& handler : handlers) {
218 gfx::Image icon;
219 const ActivityIconLoader::ActivityName activity(handler->package_name,
220 handler->activity_name);
221 const auto it = icons->find(activity);
222
223 app_info.emplace_back(
224 handler->name, it != icons->end() ? it->second.icon20 : gfx::Image());
225 }
226
227 show_intent_picker_callback_.Run(
228 navigation_handle()->GetWebContents(), app_info,
229 base::Bind(&ArcNavigationThrottle::OnIntentPickerClosed,
230 weak_ptr_factory_.GetWeakPtr(), base::Passed(&handlers)));
231 }
232
233 void ArcNavigationThrottle::OnIntentPickerClosed(
234 mojo::Array<mojom::IntentHandlerInfoPtr> handlers,
235 size_t selected_app_index,
236 CloseReason close_reason) {
237 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
238 const GURL& url = navigation_handle()->GetURL();
239 content::NavigationHandle* handle = navigation_handle();
240
241 previous_user_action_ = close_reason;
242
243 // Make sure that the instance at least supports HandleUrl.
244 auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
245 "HandleUrl", kMinVersionForHandleUrl);
246 if (!instance || selected_app_index >= handlers.size())
247 close_reason = CloseReason::ERROR;
248
249 switch (close_reason) {
250 case CloseReason::ERROR:
251 case CloseReason::DIALOG_DEACTIVATED: {
252 // If the user fails to select an option from the list, or the UI returned
253 // an error or if |selected_app_index| is not a valid index, then resume
254 // the navigation in Chrome.
255 DVLOG(1) << "User didn't select a valid option, resuming navigation.";
256 handle->Resume();
257 break;
258 }
259 case CloseReason::ALWAYS_PRESSED: {
260 // Call AddPreferredPackage if it is supported. Reusing the same
261 // |instance| is okay.
262 if (ArcIntentHelperBridge::GetIntentHelperInstance(
263 "AddPreferredPackage", kMinVersionForAddPreferredPackage)) {
264 instance->AddPreferredPackage(
265 handlers[selected_app_index]->package_name);
266 }
267 // fall through.
268 }
269 case CloseReason::JUST_ONCE_PRESSED:
270 case CloseReason::PREFERRED_ACTIVITY_FOUND: {
271 if (ArcIntentHelperBridge::IsIntentHelperPackage(
272 handlers[selected_app_index]->package_name)) {
273 handle->Resume();
274 } else {
275 instance->HandleUrl(url.spec(),
276 handlers[selected_app_index]->package_name);
277 handle->CancelDeferredNavigation(
278 content::NavigationThrottle::CANCEL_AND_IGNORE);
279 if (handle->GetWebContents()->GetController().IsInitialNavigation())
280 handle->GetWebContents()->Close();
281 }
282 break;
283 }
284 case CloseReason::INVALID: {
285 NOTREACHED();
286 return;
287 }
288 }
289
290 UMA_HISTOGRAM_ENUMERATION("Arc.IntentHandlerAction",
291 static_cast<int>(close_reason),
292 static_cast<int>(CloseReason::SIZE));
293 }
294
295 // static
296 bool ArcNavigationThrottle::ShouldOverrideUrlLoadingForTesting(
297 const GURL& previous_url,
298 const GURL& current_url) {
299 return ShouldOverrideUrlLoading(previous_url, current_url);
300 }
301
302 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698