Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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 package org.chromium.chrome.browser.externalnav; | 5 package org.chromium.chrome.browser.externalnav; |
| 6 | 6 |
| 7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
| 8 import android.app.Activity; | 8 import android.app.Activity; |
| 9 import android.content.ActivityNotFoundException; | 9 import android.content.ActivityNotFoundException; |
| 10 import android.content.ComponentName; | 10 import android.content.ComponentName; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 // - http://crbug.com/159153 : Don't override http or https URLs from th e NTP or bookmarks. | 101 // - http://crbug.com/159153 : Don't override http or https URLs from th e NTP or bookmarks. |
| 102 // - http://crbug.com/162106: Intent picker should not be presented on r eturning to a page. | 102 // - http://crbug.com/162106: Intent picker should not be presented on r eturning to a page. |
| 103 // This should be covered by not showing the picker if the core type i s reload. | 103 // This should be covered by not showing the picker if the core type i s reload. |
| 104 | 104 |
| 105 // http://crbug.com/164194 . A navigation forwards or backwards should n ever trigger | 105 // http://crbug.com/164194 . A navigation forwards or backwards should n ever trigger |
| 106 // the intent picker. | 106 // the intent picker. |
| 107 if (isForwardBackNavigation) { | 107 if (isForwardBackNavigation) { |
| 108 return OverrideUrlLoadingResult.NO_OVERRIDE; | 108 return OverrideUrlLoadingResult.NO_OVERRIDE; |
| 109 } | 109 } |
| 110 | 110 |
| 111 // http://crbug/331571 : Do not override a navigation started from user typing. | 111 Intent intent; |
| 112 // http://crbug/424029 : Need to stay in Chrome for an intent heading ex plicitly to Chrome. | 112 // perform generic parsing of the URI to turn it into an Intent. |
| 113 if (params.getRedirectHandler() != null | 113 try { |
| 114 && params.getRedirectHandler().shouldStayInChrome()) { | 114 intent = Intent.parseUri(params.getUrl(), Intent.URI_INTENT_SCHEME); |
| 115 } catch (URISyntaxException ex) { | |
| 116 Log.w(TAG, "Bad URI " + params.getUrl() + ": " + ex.getMessage()); | |
| 115 return OverrideUrlLoadingResult.NO_OVERRIDE; | 117 return OverrideUrlLoadingResult.NO_OVERRIDE; |
| 116 } | 118 } |
| 117 | 119 |
| 120 boolean hasBrowserFallbackUrl = false; | |
| 121 String browserFallbackUrl = intent.getStringExtra(EXTRA_BROWSER_FALLBACK _URL); | |
| 122 if (browserFallbackUrl != null | |
| 123 && UrlUtilities.isValidForIntentFallbackNavigation(browserFallba ckUrl)) { | |
| 124 hasBrowserFallbackUrl = true; | |
| 125 } | |
| 126 | |
| 127 if (params.getRedirectHandler() != null) { | |
| 128 // http://crbug/331571 : Do not override a navigation started from u ser typing. | |
| 129 // http://crbug/424029 : Need to stay in Chrome for an intent headin g explicitly to | |
| 130 // Chrome. | |
| 131 if (params.getRedirectHandler().shouldStayInChrome()) { | |
| 132 if (hasBrowserFallbackUrl) { | |
| 133 return clobberCurrentTabWithFallbackUrl(browserFallbackUrl, params); | |
| 134 } else { | |
| 135 return OverrideUrlLoadingResult.NO_OVERRIDE; | |
| 136 } | |
| 137 } else if (params.getRedirectHandler().shouldNotOverrideUrlLoading() ) { | |
| 138 // For instance, if this is a chained fallback URL, we ignore it . | |
| 139 return OverrideUrlLoadingResult.NO_OVERRIDE; | |
| 140 } | |
| 141 } | |
| 142 | |
| 118 // http://crbug.com/149218: We want to show the intent picker for ordina ry links, providing | 143 // http://crbug.com/149218: We want to show the intent picker for ordina ry links, providing |
| 119 // the link is not an incoming intent from another application, unless i t's a redirect (see | 144 // the link is not an incoming intent from another application, unless i t's a redirect (see |
| 120 // below). | 145 // below). |
| 121 boolean linkNotFromIntent = isLink && !isFromIntent; | 146 boolean linkNotFromIntent = isLink && !isFromIntent; |
| 122 | 147 |
| 123 boolean isOnEffectiveIntentRedirect = params.getRedirectHandler() == nul l ? false | 148 boolean isOnEffectiveIntentRedirect = params.getRedirectHandler() == nul l ? false |
| 124 : params.getRedirectHandler().isOnEffectiveIntentRedirectChain() ; | 149 : params.getRedirectHandler().isOnEffectiveIntentRedirectChain() ; |
| 125 | 150 |
| 126 // http://crbug.com/170925: We need to show the intent picker when we re ceive an intent from | 151 // http://crbug.com/170925: We need to show the intent picker when we re ceive an intent from |
| 127 // another app that 30x redirects to a YouTube/Google Maps/Play Store/Go ogle+ URL etc. | 152 // another app that 30x redirects to a YouTube/Google Maps/Play Store/Go ogle+ URL etc. |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 141 // page, there is clear intent to complete the navigation in Chrome. | 166 // page, there is clear intent to complete the navigation in Chrome. |
| 142 if (params.getReferrerUrl() != null && params.getReferrerUrl().startsWit h( | 167 if (params.getReferrerUrl() != null && params.getReferrerUrl().startsWit h( |
| 143 UrlConstants.CHROME_SCHEME) && (params.getUrl().startsWith(UrlCo nstants.HTTP_SCHEME) | 168 UrlConstants.CHROME_SCHEME) && (params.getUrl().startsWith(UrlCo nstants.HTTP_SCHEME) |
| 144 || params.getUrl().startsWith(UrlConstants.HTTPS_SCHEME) )) { | 169 || params.getUrl().startsWith(UrlConstants.HTTPS_SCHEME) )) { |
| 145 return OverrideUrlLoadingResult.NO_OVERRIDE; | 170 return OverrideUrlLoadingResult.NO_OVERRIDE; |
| 146 } | 171 } |
| 147 | 172 |
| 148 if (params.getUrl().startsWith(SCHEME_WTAI_MC)) { | 173 if (params.getUrl().startsWith(SCHEME_WTAI_MC)) { |
| 149 // wtai://wp/mc;number | 174 // wtai://wp/mc;number |
| 150 // number=string(phone-number) | 175 // number=string(phone-number) |
| 151 Intent intent = new Intent(Intent.ACTION_VIEW, | 176 mDelegate.startActivity(new Intent(Intent.ACTION_VIEW, |
| 152 Uri.parse(WebView.SCHEME_TEL | 177 Uri.parse(WebView.SCHEME_TEL |
| 153 + params.getUrl().substring(SCHEME_WTAI_MC.length()) )); | 178 + params.getUrl().substring(SCHEME_WTAI_MC.length()) ))); |
| 154 mDelegate.startActivity(intent); | |
| 155 return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT; | 179 return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT; |
| 156 } else if (params.getUrl().startsWith(SCHEME_WTAI)) { | 180 } else if (params.getUrl().startsWith(SCHEME_WTAI)) { |
| 157 // TODO: handle other WTAI schemes. | 181 // TODO: handle other WTAI schemes. |
| 158 return OverrideUrlLoadingResult.NO_OVERRIDE; | 182 return OverrideUrlLoadingResult.NO_OVERRIDE; |
| 159 } | 183 } |
| 160 | 184 |
| 161 // The "about:" schemes are internal to the browser; don't want these to | 185 // The "about:" schemes are internal to the browser; don't want these to |
| 162 // be dispatched to other apps. | 186 // be dispatched to other apps. |
| 163 if (params.getUrl().startsWith("about:")) { | 187 if (params.getUrl().startsWith("about:")) { |
| 164 return OverrideUrlLoadingResult.NO_OVERRIDE; | 188 return OverrideUrlLoadingResult.NO_OVERRIDE; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 176 if (params.getUrl().matches(".*youtube\\.com.*[?&]pairingCode=.*")) { | 200 if (params.getUrl().matches(".*youtube\\.com.*[?&]pairingCode=.*")) { |
| 177 return OverrideUrlLoadingResult.NO_OVERRIDE; | 201 return OverrideUrlLoadingResult.NO_OVERRIDE; |
| 178 } | 202 } |
| 179 | 203 |
| 180 // TODO(changwan): check if we need to handle URL even when external int ent is off. | 204 // TODO(changwan): check if we need to handle URL even when external int ent is off. |
| 181 if (CommandLine.getInstance().hasSwitch( | 205 if (CommandLine.getInstance().hasSwitch( |
| 182 ChromeSwitches.DISABLE_EXTERNAL_INTENT_REQUESTS)) { | 206 ChromeSwitches.DISABLE_EXTERNAL_INTENT_REQUESTS)) { |
| 183 return OverrideUrlLoadingResult.NO_OVERRIDE; | 207 return OverrideUrlLoadingResult.NO_OVERRIDE; |
| 184 } | 208 } |
| 185 | 209 |
| 186 Intent intent; | |
| 187 // perform generic parsing of the URI to turn it into an Intent. | |
| 188 try { | |
| 189 intent = Intent.parseUri(params.getUrl(), Intent.URI_INTENT_SCHEME); | |
| 190 } catch (URISyntaxException ex) { | |
| 191 Log.w(TAG, "Bad URI " + params.getUrl() + ": " + ex.getMessage()); | |
| 192 return OverrideUrlLoadingResult.NO_OVERRIDE; | |
| 193 } | |
| 194 | |
| 195 boolean hasBrowserFallbackUrl = false; | |
| 196 String browserFallbackUrl = intent.getStringExtra(EXTRA_BROWSER_FALLBACK _URL); | |
| 197 if (browserFallbackUrl != null | |
| 198 && UrlUtilities.isValidForIntentFallbackNavigation(browserFallba ckUrl)) { | |
| 199 hasBrowserFallbackUrl = true; | |
| 200 } | |
| 201 | |
| 202 // check whether the intent can be resolved. If not, we will see | 210 // check whether the intent can be resolved. If not, we will see |
| 203 // whether we can download it from the Market. | 211 // whether we can download it from the Market. |
| 204 if (!mDelegate.canResolveActivity(intent)) { | 212 if (!mDelegate.canResolveActivity(intent)) { |
| 205 if (hasBrowserFallbackUrl) { | 213 if (hasBrowserFallbackUrl) { |
| 206 // NOTE: any further redirection from fall-back URL should not o verride URL loading. | 214 return clobberCurrentTabWithFallbackUrl(browserFallbackUrl, para ms); |
| 207 // Otherwise, it can be used in chain for fingerprinting multipl e app installation | |
| 208 // status in one shot. In order to prevent this scenario, we not ify redirection | |
| 209 // handler that redirection from the current navigation should s tay in Chrome. | |
| 210 if (params.getRedirectHandler() != null) { | |
| 211 params.getRedirectHandler() | |
| 212 .setShouldStayInChromeUntilNewUrlLoading(); | |
| 213 } | |
| 214 return mDelegate.clobberCurrentTab(browserFallbackUrl, params.ge tReferrerUrl(), | |
| 215 params.getTab()); | |
| 216 } | 215 } |
| 217 String packagename = intent.getPackage(); | 216 String packagename = intent.getPackage(); |
| 218 if (packagename != null) { | 217 if (packagename != null) { |
| 219 try { | 218 try { |
| 220 intent = new Intent(Intent.ACTION_VIEW, Uri.parse( | 219 intent = new Intent(Intent.ACTION_VIEW, Uri.parse( |
| 221 "market://details?id=" + packagename | 220 "market://details?id=" + packagename |
| 222 + "&referrer=" + mDelegate.getPackageName())); | 221 + "&referrer=" + mDelegate.getPackageName())); |
| 223 intent.addCategory(Intent.CATEGORY_BROWSABLE); | 222 intent.addCategory(Intent.CATEGORY_BROWSABLE); |
| 224 intent.setPackage("com.android.vending"); | 223 intent.setPackage("com.android.vending"); |
| 225 mDelegate.startActivity(intent); | 224 mDelegate.startActivity(intent); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 332 } | 331 } |
| 333 } catch (ActivityNotFoundException ex) { | 332 } catch (ActivityNotFoundException ex) { |
| 334 // Ignore the error. If no application can handle the URL, | 333 // Ignore the error. If no application can handle the URL, |
| 335 // assume the browser can handle it. | 334 // assume the browser can handle it. |
| 336 } | 335 } |
| 337 | 336 |
| 338 return OverrideUrlLoadingResult.NO_OVERRIDE; | 337 return OverrideUrlLoadingResult.NO_OVERRIDE; |
| 339 } | 338 } |
| 340 | 339 |
| 341 /** | 340 /** |
| 341 * Clobber the current tab with fallback URL. | |
| 342 * | |
| 343 * @param browserFallbackUrl The fallback URL. | |
| 344 * @param params The external navigation params. | |
| 345 * @return {@link OverrideUrlLoadingResult} (if the tab was clobbered, or we launched an | |
| 346 *intent.) | |
|
Maria
2015/03/27 00:12:59
indent 8 on second line and don't need parenthesis
Changwan Ryu
2015/03/27 02:09:50
Done.
| |
| 347 */ | |
| 348 private OverrideUrlLoadingResult clobberCurrentTabWithFallbackUrl( | |
| 349 String browserFallbackUrl, ExternalNavigationParams params) { | |
| 350 // NOTE: any further redirection from fall-back URL should not override URL loading. | |
| 351 // Otherwise, it can be used in chain for fingerprinting multiple app in stallation | |
| 352 // status in one shot. In order to prevent this scenario, we notify redi rection | |
| 353 // handler that redirection from the current navigation should stay in C hrome. | |
| 354 if (params.getRedirectHandler() != null) { | |
| 355 params.getRedirectHandler().setShouldNotOverrideUrlLoadingUntilNewUr lLoading(); | |
| 356 } | |
| 357 return mDelegate.clobberCurrentTab( | |
| 358 browserFallbackUrl, params.getReferrerUrl(), params.getTab()); | |
| 359 } | |
| 360 | |
| 361 /** | |
| 342 * @return Whether the |url| could be handled by an external application on the system. | 362 * @return Whether the |url| could be handled by an external application on the system. |
| 343 */ | 363 */ |
| 344 public boolean canExternalAppHandleUrl(String url) { | 364 public boolean canExternalAppHandleUrl(String url) { |
| 345 if (url.startsWith(SCHEME_WTAI_MC)) return true; | 365 if (url.startsWith(SCHEME_WTAI_MC)) return true; |
| 346 try { | 366 try { |
| 347 Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); | 367 Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); |
| 348 return intent.getPackage() != null || mDelegate.canResolveActivity(i ntent); | 368 return intent.getPackage() != null || mDelegate.canResolveActivity(i ntent); |
| 349 } catch (URISyntaxException ex) { | 369 } catch (URISyntaxException ex) { |
| 350 // Ignore the error. | 370 // Ignore the error. |
| 351 } | 371 } |
| 352 return false; | 372 return false; |
| 353 } | 373 } |
| 354 } | 374 } |
| OLD | NEW |