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
import org.chromium.chrome.browser.snackbar.Snackbar;
import org.chromium.chrome.browser.snackbar.SnackbarManager;
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.ui.base.PageTransition;
......@@ -304,10 +307,31 @@ public class LocaleManager {
return;
}
showPromoDialog(dialogCreator);
if (VrIntentUtils.isVrIntent(activity.getIntent()) || VrShellDelegate.isInVr()) {
showPromoDialogForVr(dialogCreator, activity);
} else {
showPromoDialog(dialogCreator);
}
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) {
try {
dialogCreator.call().show();
......
......@@ -64,7 +64,7 @@ public interface VrShell extends VrDialogManager, VrToastManager {
/**
* Requests to exit VR.
*/
void requestToExitVr(@UiUnsupportedMode int reason);
void requestToExitVr(@UiUnsupportedMode int reason, boolean showExitPromptBeforeDoff);
/**
* Triggers VrShell to navigate forward.
......
......@@ -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
// the URL bar security icon.
private OnExitVrRequestListener mOnExitVrRequestListener;
private Runnable mPendingExitVrRequest;
private boolean mExitedDueToUnsupportedMode;
private boolean mExitingCct;
private boolean mPaused;
......@@ -365,6 +366,11 @@ public class VrShellDelegate
sVrModeObservers.remove(observer);
}
public static void forceExitVrImmediately() {
if (sInstance == null) return;
sInstance.shutdownVr(true, true);
}
/**
* See {@link Activity#onActivityResult}.
*/
......@@ -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) {
requestToExitVr(listener, UiUnsupportedMode.GENERIC_UNSUPPORTED_FEATURE);
}
......@@ -544,7 +579,7 @@ public class VrShellDelegate
listener.onSucceeded();
return;
}
sInstance.requestToExitVrInternal(listener, reason);
sInstance.requestToExitVrInternal(listener, reason, true);
}
/**
......@@ -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
......@@ -1490,8 +1539,8 @@ public class VrShellDelegate
return ENTER_VR_REQUESTED;
}
private void requestToExitVrInternal(
OnExitVrRequestListener listener, @UiUnsupportedMode int reason) {
private void requestToExitVrInternal(OnExitVrRequestListener listener,
@UiUnsupportedMode int reason, boolean showExitPromptBeforeDoff) {
assert listener != null;
// If we are currently processing another request, deny the request.
if (mOnExitVrRequestListener != null) {
......@@ -1499,8 +1548,8 @@ public class VrShellDelegate
return;
}
mOnExitVrRequestListener = listener;
mShowingExitVrPrompt = true;
mVrShell.requestToExitVr(reason);
mShowingExitVrPrompt = showExitPromptBeforeDoff;
mVrShell.requestToExitVr(reason, showExitPromptBeforeDoff);
}
private void exitWebVRAndClearState() {
......@@ -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) {
// This means that Chrome was started with a VR intent, so we should enter VR.
......
......@@ -908,8 +908,14 @@ public class VrShellImpl
}
@Override
public void requestToExitVr(@UiUnsupportedMode int reason) {
if (mNativeVrShell != 0) nativeRequestToExitVr(mNativeVrShell, reason);
public void requestToExitVr(@UiUnsupportedMode int reason, boolean showExitPromptBeforeDoff) {
if (mNativeVrShell == 0) return;
if (showExitPromptBeforeDoff) {
nativeRequestToExitVr(mNativeVrShell, reason);
} else {
nativeLogUnsupportedModeUserMetric(mNativeVrShell, reason);
mDelegate.onExitVrRequestResult(true);
}
}
@CalledByNative
......
......@@ -839,6 +839,9 @@ void VrShell::OnUnsupportedMode(UiUnsupportedMode mode) {
Java_VrShellImpl_onNeedsKeyboardUpdate(env, j_vr_shell_);
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:
NOTREACHED(); // Should never be used as a mode.
return;
......
......@@ -155,6 +155,9 @@ void Ui::ShowExitVrPrompt(UiUnsupportedMode reason) {
case UiUnsupportedMode::kNeedsKeyboardUpdate:
model_->active_modal_prompt_type = kModalPromptTypeUpdateKeyboard;
return;
// kSearchEnginePromo should DOFF directly. It should never try to change
// the state of UI.
case UiUnsupportedMode::kSearchEnginePromo:
case UiUnsupportedMode::kCount:
NOTREACHED(); // Should never be used as a mode (when |enabled| is true).
return;
......
......@@ -19,6 +19,7 @@ enum class UiUnsupportedMode : int {
kVoiceSearchNeedsRecordAudioOsPermission = 4, // TODO(ddorwin): Android only.
kGenericUnsupportedFeature = 5,
kNeedsKeyboardUpdate = 6,
kSearchEnginePromo = 7,
// This must be last.
kCount,
};
......
......@@ -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="5" label="A non-specific unsupported feature was encountered"/>
<int value="6" label="The keyboard version is out-of-date"/>
<int value="7" label="The default search engine wasn't selected"/>
</enum>
<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