Commit 50e2b393 authored by Biao She's avatar Biao She Committed by Commit Bot

Force exit VR if we are about to show Search engine selection dialog

Bug: 819875
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_vr;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I95e91504b6e28ac2f762881dde31924f05c2cf6e
Reviewed-on: https://chromium-review.googlesource.com/987388Reviewed-by: default avatarYash Malik <ymalik@chromium.org>
Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Reviewed-by: default avatarTibor Goldschwendt <tiborg@chromium.org>
Commit-Queue: Biao She <bshe@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548467}
parent 4d43c713
...@@ -31,6 +31,9 @@ import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl ...@@ -31,6 +31,9 @@ import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl
import org.chromium.chrome.browser.snackbar.Snackbar; import org.chromium.chrome.browser.snackbar.Snackbar;
import org.chromium.chrome.browser.snackbar.SnackbarManager; import org.chromium.chrome.browser.snackbar.SnackbarManager;
import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
import org.chromium.chrome.browser.vr_shell.OnExitVrRequestListener;
import org.chromium.chrome.browser.vr_shell.VrIntentUtils;
import org.chromium.chrome.browser.vr_shell.VrShellDelegate;
import org.chromium.chrome.browser.widget.PromoDialog; import org.chromium.chrome.browser.widget.PromoDialog;
import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.PageTransition;
...@@ -304,10 +307,31 @@ public class LocaleManager { ...@@ -304,10 +307,31 @@ public class LocaleManager {
return; return;
} }
showPromoDialog(dialogCreator); if (VrIntentUtils.isVrIntent(activity.getIntent()) || VrShellDelegate.isInVr()) {
showPromoDialogForVr(dialogCreator, activity);
} else {
showPromoDialog(dialogCreator);
}
mSearchEnginePromoShownThisSession = true; mSearchEnginePromoShownThisSession = true;
} }
private void showPromoDialogForVr(Callable<PromoDialog> dialogCreator, Activity activity) {
VrShellDelegate.requestToExitVrForSearchEnginePromoDialog(new OnExitVrRequestListener() {
@Override
public void onSucceeded() {
showPromoDialog(dialogCreator);
}
@Override
public void onDenied() {
// We need to make sure that the dialog shows up even if user denied to
// leave VR.
VrShellDelegate.forceExitVrImmediately();
showPromoDialog(dialogCreator);
}
}, activity);
}
private void showPromoDialog(Callable<PromoDialog> dialogCreator) { private void showPromoDialog(Callable<PromoDialog> dialogCreator) {
try { try {
dialogCreator.call().show(); dialogCreator.call().show();
......
...@@ -64,7 +64,7 @@ public interface VrShell extends VrDialogManager, VrToastManager { ...@@ -64,7 +64,7 @@ public interface VrShell extends VrDialogManager, VrToastManager {
/** /**
* Requests to exit VR. * Requests to exit VR.
*/ */
void requestToExitVr(@UiUnsupportedMode int reason); void requestToExitVr(@UiUnsupportedMode int reason, boolean showExitPromptBeforeDoff);
/** /**
* Triggers VrShell to navigate forward. * Triggers VrShell to navigate forward.
......
...@@ -184,6 +184,7 @@ public class VrShellDelegate ...@@ -184,6 +184,7 @@ public class VrShellDelegate
// Listener to be called once we exited VR due to to an unsupported mode, e.g. the user clicked // Listener to be called once we exited VR due to to an unsupported mode, e.g. the user clicked
// the URL bar security icon. // the URL bar security icon.
private OnExitVrRequestListener mOnExitVrRequestListener; private OnExitVrRequestListener mOnExitVrRequestListener;
private Runnable mPendingExitVrRequest;
private boolean mExitedDueToUnsupportedMode; private boolean mExitedDueToUnsupportedMode;
private boolean mExitingCct; private boolean mExitingCct;
private boolean mPaused; private boolean mPaused;
...@@ -365,6 +366,11 @@ public class VrShellDelegate ...@@ -365,6 +366,11 @@ public class VrShellDelegate
sVrModeObservers.remove(observer); sVrModeObservers.remove(observer);
} }
public static void forceExitVrImmediately() {
if (sInstance == null) return;
sInstance.shutdownVr(true, true);
}
/** /**
* See {@link Activity#onActivityResult}. * See {@link Activity#onActivityResult}.
*/ */
...@@ -521,6 +527,35 @@ public class VrShellDelegate ...@@ -521,6 +527,35 @@ public class VrShellDelegate
} }
} }
public static void requestToExitVrForSearchEnginePromoDialog(
OnExitVrRequestListener listener, Activity activity) {
// When call site requests to exit VR, depend on the timing, Chrome may not in VR yet
// (Chrome only enter VR after onNewIntentWithNative is called in the cold start case).
// While not in VR, calling requestToExitVr would immediately notify listener that exit VR
// succeed (without showing DOFF screen). If call site decide to show 2D UI when exit VR
// succeeded, it leads to case that 2D UI is showing on top of VR when Chrome eventually
// enters VR. To prevent this from happening, we set mPendingExitVrRequest which should be
// executed at runPendingExitVrTask. runPendingExitVrTask is called after it is safe to
// request exit VR.
if (isInVr()) {
sInstance.requestToExitVrInternal(
listener, UiUnsupportedMode.SEARCH_ENGINE_PROMO, false);
} else {
// Making sure that we response to this request as it is very important that search
// engine promo dialog isn't ignored due to VR.
assert VrIntentUtils.isVrIntent(activity.getIntent());
VrShellDelegate instance = getInstance();
if (instance == null) {
listener.onDenied();
return;
}
sInstance.mPendingExitVrRequest = () -> {
sInstance.requestToExitVrInternal(
listener, UiUnsupportedMode.SEARCH_ENGINE_PROMO, false);
};
}
}
public static void requestToExitVr(OnExitVrRequestListener listener) { public static void requestToExitVr(OnExitVrRequestListener listener) {
requestToExitVr(listener, UiUnsupportedMode.GENERIC_UNSUPPORTED_FEATURE); requestToExitVr(listener, UiUnsupportedMode.GENERIC_UNSUPPORTED_FEATURE);
} }
...@@ -544,7 +579,7 @@ public class VrShellDelegate ...@@ -544,7 +579,7 @@ public class VrShellDelegate
listener.onSucceeded(); listener.onSucceeded();
return; return;
} }
sInstance.requestToExitVrInternal(listener, reason); sInstance.requestToExitVrInternal(listener, reason, true);
} }
/** /**
...@@ -1350,6 +1385,20 @@ public class VrShellDelegate ...@@ -1350,6 +1385,20 @@ public class VrShellDelegate
} }
} }
} }
// If canceling entry animation started, the activity is paused first and then expect a
// onResume is called next. We don't want to disrupt this process by calling
// runPendingExitVrTask which will show DOFF sceeen. DOFF might trigger onStop before
// onResume which will crash Chrome. So if we know that we are canceling animation, we don't
// call runPendingExitVrTask.
if (!mCancellingEntryAnimation) {
runPendingExitVrTask();
}
}
private void runPendingExitVrTask() {
if (mPendingExitVrRequest == null) return;
mPendingExitVrRequest.run();
mPendingExitVrRequest = null;
} }
@Override @Override
...@@ -1490,8 +1539,8 @@ public class VrShellDelegate ...@@ -1490,8 +1539,8 @@ public class VrShellDelegate
return ENTER_VR_REQUESTED; return ENTER_VR_REQUESTED;
} }
private void requestToExitVrInternal( private void requestToExitVrInternal(OnExitVrRequestListener listener,
OnExitVrRequestListener listener, @UiUnsupportedMode int reason) { @UiUnsupportedMode int reason, boolean showExitPromptBeforeDoff) {
assert listener != null; assert listener != null;
// If we are currently processing another request, deny the request. // If we are currently processing another request, deny the request.
if (mOnExitVrRequestListener != null) { if (mOnExitVrRequestListener != null) {
...@@ -1499,8 +1548,8 @@ public class VrShellDelegate ...@@ -1499,8 +1548,8 @@ public class VrShellDelegate
return; return;
} }
mOnExitVrRequestListener = listener; mOnExitVrRequestListener = listener;
mShowingExitVrPrompt = true; mShowingExitVrPrompt = showExitPromptBeforeDoff;
mVrShell.requestToExitVr(reason); mVrShell.requestToExitVr(reason, showExitPromptBeforeDoff);
} }
private void exitWebVRAndClearState() { private void exitWebVRAndClearState() {
...@@ -1606,7 +1655,12 @@ public class VrShellDelegate ...@@ -1606,7 +1655,12 @@ public class VrShellDelegate
}); });
} }
mCancellingEntryAnimation = false; if (mCancellingEntryAnimation) {
// If we know this onResume is called after cancel animation finished, it is safe to
// request exit VR and show DOFF.
runPendingExitVrTask();
mCancellingEntryAnimation = false;
}
if (mEnterVrOnStartup) { if (mEnterVrOnStartup) {
// This means that Chrome was started with a VR intent, so we should enter VR. // This means that Chrome was started with a VR intent, so we should enter VR.
......
...@@ -908,8 +908,14 @@ public class VrShellImpl ...@@ -908,8 +908,14 @@ public class VrShellImpl
} }
@Override @Override
public void requestToExitVr(@UiUnsupportedMode int reason) { public void requestToExitVr(@UiUnsupportedMode int reason, boolean showExitPromptBeforeDoff) {
if (mNativeVrShell != 0) nativeRequestToExitVr(mNativeVrShell, reason); if (mNativeVrShell == 0) return;
if (showExitPromptBeforeDoff) {
nativeRequestToExitVr(mNativeVrShell, reason);
} else {
nativeLogUnsupportedModeUserMetric(mNativeVrShell, reason);
mDelegate.onExitVrRequestResult(true);
}
} }
@CalledByNative @CalledByNative
......
...@@ -839,6 +839,9 @@ void VrShell::OnUnsupportedMode(UiUnsupportedMode mode) { ...@@ -839,6 +839,9 @@ void VrShell::OnUnsupportedMode(UiUnsupportedMode mode) {
Java_VrShellImpl_onNeedsKeyboardUpdate(env, j_vr_shell_); Java_VrShellImpl_onNeedsKeyboardUpdate(env, j_vr_shell_);
return; return;
} }
// kSearchEnginePromo should directly DOFF without showing a promo. So it
// should never be used from VR ui thread.
case UiUnsupportedMode::kSearchEnginePromo:
case UiUnsupportedMode::kCount: case UiUnsupportedMode::kCount:
NOTREACHED(); // Should never be used as a mode. NOTREACHED(); // Should never be used as a mode.
return; return;
......
...@@ -155,6 +155,9 @@ void Ui::ShowExitVrPrompt(UiUnsupportedMode reason) { ...@@ -155,6 +155,9 @@ void Ui::ShowExitVrPrompt(UiUnsupportedMode reason) {
case UiUnsupportedMode::kNeedsKeyboardUpdate: case UiUnsupportedMode::kNeedsKeyboardUpdate:
model_->active_modal_prompt_type = kModalPromptTypeUpdateKeyboard; model_->active_modal_prompt_type = kModalPromptTypeUpdateKeyboard;
return; return;
// kSearchEnginePromo should DOFF directly. It should never try to change
// the state of UI.
case UiUnsupportedMode::kSearchEnginePromo:
case UiUnsupportedMode::kCount: case UiUnsupportedMode::kCount:
NOTREACHED(); // Should never be used as a mode (when |enabled| is true). NOTREACHED(); // Should never be used as a mode (when |enabled| is true).
return; return;
......
...@@ -19,6 +19,7 @@ enum class UiUnsupportedMode : int { ...@@ -19,6 +19,7 @@ enum class UiUnsupportedMode : int {
kVoiceSearchNeedsRecordAudioOsPermission = 4, // TODO(ddorwin): Android only. kVoiceSearchNeedsRecordAudioOsPermission = 4, // TODO(ddorwin): Android only.
kGenericUnsupportedFeature = 5, kGenericUnsupportedFeature = 5,
kNeedsKeyboardUpdate = 6, kNeedsKeyboardUpdate = 6,
kSearchEnginePromo = 7,
// This must be last. // This must be last.
kCount, kCount,
}; };
......
...@@ -45986,6 +45986,7 @@ Full version information for the fingerprint enum values: ...@@ -45986,6 +45986,7 @@ Full version information for the fingerprint enum values:
<int value="4" label="Chrome needs audio permission for voice input"/> <int value="4" label="Chrome needs audio permission for voice input"/>
<int value="5" label="A non-specific unsupported feature was encountered"/> <int value="5" label="A non-specific unsupported feature was encountered"/>
<int value="6" label="The keyboard version is out-of-date"/> <int value="6" label="The keyboard version is out-of-date"/>
<int value="7" label="The default search engine wasn't selected"/>
</enum> </enum>
<enum name="VRViewerType"> <enum name="VRViewerType">
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