Commit 32ad2887 authored by Troy Hildebrandt's avatar Troy Hildebrandt Committed by Commit Bot

Catch BadTokenExceptions displaying alert dialogs for incognito intents.

It appears that on certain devices/variations of Android, the
implementation of Dialog.show() can end up with the same ViewRootImpl
being added to the WindowManager twice, resulting in a
BadTokenException.

This change adds a safer variant of shouldShowIncognitoIntent, the
aptly named shouldShowIncognitoIntentSafe, that returns a boolean to
indicate whether we successfully showed the alert dialog or not,
allowing us to log the error but handle the failure without crashing.

TBR=bshe@chromium.org

Bug: 782602
Change-Id: Iea5bd3b8f45c9824e34f581d208653a206b65c1e
Reviewed-on: https://chromium-review.googlesource.com/801257
Commit-Queue: Troy Hildebrandt <thildebr@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#520773}
parent 8a13f005
...@@ -75,7 +75,8 @@ interface ExternalNavigationDelegate { ...@@ -75,7 +75,8 @@ interface ExternalNavigationDelegate {
/** /**
* Display a dialog warning the user that they may be leaving Chrome by starting this * Display a dialog warning the user that they may be leaving Chrome by starting this
* intent. Give the user the opportunity to cancel the action. And if it is canceled, a * intent. Give the user the opportunity to cancel the action. And if it is canceled, a
* navigation will happen in Chrome. * navigation will happen in Chrome. Catches BadTokenExceptions caused by showing the dialog
* on certain devices. (crbug.com/782602)
* @param intent The intent for external application that will be sent. * @param intent The intent for external application that will be sent.
* @param referrerUrl The referrer for the current navigation. * @param referrerUrl The referrer for the current navigation.
* @param fallbackUrl The URL to load if the user doesn't proceed with external intent. * @param fallbackUrl The URL to load if the user doesn't proceed with external intent.
...@@ -83,8 +84,9 @@ interface ExternalNavigationDelegate { ...@@ -83,8 +84,9 @@ interface ExternalNavigationDelegate {
* @param needsToCloseTab Whether the current tab has to be closed after the intent is sent. * @param needsToCloseTab Whether the current tab has to be closed after the intent is sent.
* @param proxy Whether we need to proxy the intent through AuthenticatedProxyActivity (this is * @param proxy Whether we need to proxy the intent through AuthenticatedProxyActivity (this is
* used by Instant Apps intents. * used by Instant Apps intents.
* @return True if the function returned error free, false if it threw an exception.
*/ */
void startIncognitoIntent(Intent intent, String referrerUrl, String fallbackUrl, Tab tab, boolean startIncognitoIntent(Intent intent, String referrerUrl, String fallbackUrl, Tab tab,
boolean needsToCloseTab, boolean proxy); boolean needsToCloseTab, boolean proxy);
/** /**
......
...@@ -21,6 +21,7 @@ import android.provider.Browser; ...@@ -21,6 +21,7 @@ import android.provider.Browser;
import android.provider.Telephony; import android.provider.Telephony;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.WindowManager.BadTokenException;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import org.chromium.base.ApplicationState; import org.chromium.base.ApplicationState;
...@@ -379,7 +380,19 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat ...@@ -379,7 +380,19 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
} }
@Override @Override
public void startIncognitoIntent(final Intent intent, final String referrerUrl, public boolean startIncognitoIntent(final Intent intent, final String referrerUrl,
final String fallbackUrl, final Tab tab, final boolean needsToCloseTab,
final boolean proxy) {
try {
startIncognitoIntentInternal(
intent, referrerUrl, fallbackUrl, tab, needsToCloseTab, proxy);
} catch (BadTokenException e) {
return false;
}
return true;
}
private void startIncognitoIntentInternal(final Intent intent, final String referrerUrl,
final String fallbackUrl, final Tab tab, final boolean needsToCloseTab, final String fallbackUrl, final Tab tab, final boolean needsToCloseTab,
final boolean proxy) { final boolean proxy) {
Context context = tab.getWindowAndroid().getContext().get(); Context context = tab.getWindowAndroid().getContext().get();
......
...@@ -493,10 +493,13 @@ public class ExternalNavigationHandler { ...@@ -493,10 +493,13 @@ public class ExternalNavigationHandler {
if (params.isIncognito() && !mDelegate.willChromeHandleIntent(intent)) { if (params.isIncognito() && !mDelegate.willChromeHandleIntent(intent)) {
// This intent may leave Chrome. Warn the user that incognito does not carry over // This intent may leave Chrome. Warn the user that incognito does not carry over
// to apps out side of Chrome. // to apps out side of Chrome.
mDelegate.startIncognitoIntent(intent, params.getReferrerUrl(), if (!mDelegate.startIncognitoIntent(intent, params.getReferrerUrl(),
hasBrowserFallbackUrl ? browserFallbackUrl : null, params.getTab(), hasBrowserFallbackUrl ? browserFallbackUrl : null, params.getTab(),
params.shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent(), params.shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent(),
shouldProxyForInstantApps); shouldProxyForInstantApps)) {
if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Failed to show incognito alert dialog.");
return OverrideUrlLoadingResult.NO_OVERRIDE;
}
if (DEBUG) Log.i(TAG, "OVERRIDE_WITH_ASYNC_ACTION: Incognito navigation out"); if (DEBUG) Log.i(TAG, "OVERRIDE_WITH_ASYNC_ACTION: Incognito navigation out");
return OverrideUrlLoadingResult.OVERRIDE_WITH_ASYNC_ACTION; return OverrideUrlLoadingResult.OVERRIDE_WITH_ASYNC_ACTION;
} }
...@@ -576,9 +579,13 @@ public class ExternalNavigationHandler { ...@@ -576,9 +579,13 @@ public class ExternalNavigationHandler {
intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(params.getReferrerUrl())); intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(params.getReferrerUrl()));
} }
if (params.isIncognito()) { if (params.isIncognito()) {
mDelegate.startIncognitoIntent(intent, params.getReferrerUrl(), null, if (!mDelegate.startIncognitoIntent(intent, params.getReferrerUrl(), null,
params.getTab(), params.getTab(),
params.shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent(), false); params.shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent(),
false)) {
if (DEBUG) Log.i(TAG, "NO_OVERRIDE: Failed to show incognito alert dialog.");
return OverrideUrlLoadingResult.NO_OVERRIDE;
}
if (DEBUG) Log.i(TAG, "OVERRIDE_WITH_ASYNC_ACTION: Incognito intent to Play Store"); if (DEBUG) Log.i(TAG, "OVERRIDE_WITH_ASYNC_ACTION: Incognito intent to Play Store");
return OverrideUrlLoadingResult.OVERRIDE_WITH_ASYNC_ACTION; return OverrideUrlLoadingResult.OVERRIDE_WITH_ASYNC_ACTION;
} else { } else {
......
...@@ -28,9 +28,10 @@ public class VrExternalNavigationDelegate extends ExternalNavigationDelegateImpl ...@@ -28,9 +28,10 @@ public class VrExternalNavigationDelegate extends ExternalNavigationDelegateImpl
} }
@Override @Override
public void startIncognitoIntent(Intent intent, String referrerUrl, String fallbackUrl, Tab tab, public boolean startIncognitoIntent(Intent intent, String referrerUrl, String fallbackUrl,
boolean needsToCloseTab, boolean proxy) { Tab tab, boolean needsToCloseTab, boolean proxy) {
VrShellDelegate.showDoffAndExitVr(false); VrShellDelegate.showDoffAndExitVr(false);
return true;
} }
@Override @Override
......
...@@ -1385,10 +1385,11 @@ public class ExternalNavigationHandlerTest { ...@@ -1385,10 +1385,11 @@ public class ExternalNavigationHandlerTest {
} }
@Override @Override
public void startIncognitoIntent(Intent intent, String referrerUrl, String fallbackUrl, public boolean startIncognitoIntent(Intent intent, String referrerUrl, String fallbackUrl,
Tab tab, boolean needsToCloseTab, boolean proxy) { Tab tab, boolean needsToCloseTab, boolean proxy) {
startActivityIntent = intent; startActivityIntent = intent;
startIncognitoIntentCalled = true; startIncognitoIntentCalled = true;
return true;
} }
@Override @Override
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment