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

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java

Issue 2969923002: [vr] Hide 2D UI when entering VR for WebVR auto-presentation (Closed)
Patch Set: address mthiesse's review comments Created 3 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 2a7e7b4e505827d4e199c608835d9db9e24d0743..fa03b4b9826aa02365dbcc1eaead88acf8b39ca0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -23,6 +23,7 @@ import android.os.Handler;
import android.os.StrictMode;
import android.os.SystemClock;
import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.view.Choreographer;
import android.view.Choreographer.FrameCallback;
@@ -56,6 +57,7 @@ import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.chrome.browser.webapps.WebappActivity;
+import org.chromium.ui.UiUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -115,6 +117,7 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
private static VrShellDelegate sInstance;
private static VrBroadcastReceiver sVrBroadcastReceiver;
private static boolean sRegisteredDaydreamHook = false;
+ private static View sBlackOverlayView;
private ChromeActivity mActivity;
@@ -169,8 +172,6 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
// presentation experience.
private boolean mVrBrowserUsed;
- private View mOverlayView;
-
private final VSyncEstimator mVSyncEstimator;
private static final class VrBroadcastReceiver extends BroadcastReceiver {
@@ -197,7 +198,7 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
// resuming the Activity, see the comment about the custom animation below.
// However, if we're already in VR (in one of the cases where we chose not to exit
// VR before the DON flow), we don't need to add the overlay.
- if (!sInstance.mInVr) sInstance.addOverlayView();
+ if (!sInstance.mInVr) addBlackOverlayViewForActivity(sInstance.mActivity);
sInstance.mNeedsAnimationCancel = !sInstance.mInVr;
// We start the Activity with a custom animation that keeps it hidden while starting
@@ -235,14 +236,17 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
/**
* Called when the native library is first available.
*/
- public static void onNativeLibraryAvailable() {
+ public static void onNativeLibraryAvailable(ChromeActivity activity, @Nullable Intent intent) {
// Check if VR classes are available before trying to use them. Note that the native
// vr_shell_delegate.cc is compiled out of unsupported platforms (like x86).
VrClassesWrapper wrapper = getVrClassesWrapper();
if (wrapper == null) return;
nativeOnLibraryAvailable();
- if (sInstance != null && sInstance.mAutopresentWebVr) {
- sInstance.enterVr(false);
+ if (intent == null) return;
+
+ onNewIntentWithNative(activity, intent);
+ if (sInstance != null) {
+ sInstance.cancelStartupAnimationIfNeeded();
}
}
@@ -776,8 +780,7 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
maybeSetPresentResult(true, donSuceeded);
mVrShell.getContainer().setOnSystemUiVisibilityChangeListener(this);
- removeOverlayView();
-
+ removeBlackOverlayView();
if (!donSuceeded && !mAutopresentWebVr && isDaydreamCurrentViewer()) {
// TODO(mthiesse): This is a VERY dirty hack. We need to know whether or not entering VR
// will trigger the DON flow, so that we can wait for it to complete before we let the
@@ -797,28 +800,87 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
}
}
+ private static void addBlackOverlayViewForActivity(ChromeActivity activity) {
+ if (sBlackOverlayView != null) return;
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+ WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
+ FrameLayout decor = (FrameLayout) activity.getWindow().getDecorView();
+ sBlackOverlayView = new View(activity);
+ sBlackOverlayView.setBackgroundColor(Color.BLACK);
+ activity.getWindow().addContentView(sBlackOverlayView, params);
+ }
+
+ private static void removeBlackOverlayView() {
+ if (sBlackOverlayView != null) UiUtils.removeViewFromParent(sBlackOverlayView);
+ sBlackOverlayView = null;
+ }
+
+ private static boolean isTrustedDaydreamIntent(Intent intent) {
+ return isVrIntent(intent)
+ && IntentHandler.isIntentFromTrustedApp(intent, DAYDREAM_HOME_PACKAGE);
+ }
+
private void onAutopresentIntent() {
// Autopresent intents are only expected from trusted first party apps while
// we're not in vr.
assert !mInVr;
- mAutopresentWebVr = true;
mDonSucceeded = true;
+ mAutopresentWebVr = true;
+ }
+
+ private void onVrIntent() {
+ // We assume that when we get a VR intent, we're in the headset.
+ mNeedsAnimationCancel = true;
}
/**
* This is called every time ChromeActivity gets a new intent.
*/
- public static void onNewIntent(ChromeActivity activity, Intent intent) {
- if (IntentUtils.safeGetBooleanExtra(intent, DAYDREAM_VR_EXTRA, false)
+ public static void onNewIntentWithNative(ChromeActivity activity, Intent intent) {
+ if (!isVrIntent(intent) || !activitySupportsVrBrowsing(activity)) return;
+ VrShellDelegate instance = getInstance(activity);
+ if (instance == null) return;
+ instance.onVrIntent();
+ if (isTrustedDaydreamIntent(intent)
&& ChromeFeatureList.isEnabled(ChromeFeatureList.WEBVR_AUTOPRESENT)
- && activitySupportsAutopresentation(activity)
- && IntentHandler.isIntentFromTrustedApp(intent, DAYDREAM_HOME_PACKAGE)) {
- VrShellDelegate instance = getInstance(activity);
- if (instance == null) return;
+ && activitySupportsAutopresentation(activity)) {
instance.onAutopresentIntent();
}
}
+ /**
+ * This is called when ChromeTabbedActivity gets a new intent before native is initialized.
+ */
+ public static void maybeHandleVrIntentPreNative(ChromeActivity activity, Intent intent) {
+ if (isTrustedDaydreamIntent(intent)) {
+ // We add a black overlay view so that we can show black while the VR UI is loading.
+ // Note that this alone isn't sufficient to prevent 2D UI from showing when
+ // auto-presenting WebVR. See comment about the custom animation in {@link
+ // getVrIntentOptions}.
+ addBlackOverlayViewForActivity(activity);
+ }
+ }
+
+ /**
+ * @return Whether or not the given intent is a VR-specific intent.
+ */
+ public static boolean isVrIntent(Intent intent) {
+ return IntentUtils.safeGetBooleanExtra(intent, DAYDREAM_VR_EXTRA, false);
+ }
+
+ /**
+ * @return Options that a VR-specific Chrome activity should be launched with.
+ */
+ public static Bundle getVrIntentOptions(Context context) {
+ // These options are used to start the Activity with a custom animation to keep it hidden
+ // for a few hundread milliseconds - enough time for us to draw the first black view.
+ // The animation is sufficient to hide the 2D screenshot but not to the 2D UI while the
+ // WebVR page is being loaded because the animation is somehow cancelled when we try to
+ // enter VR (I don't know what's cancelling it). To hide the 2D UI, we resort to the black
+ // overlay view added in {@link startWithVrIntentPreNative}.
+ return ActivityOptions.makeCustomAnimation(context, R.anim.stay_hidden, 0).toBundle();
+ }
+
@Override
public void onSystemUiVisibilityChange(int visibility) {
if (mInVr && !isWindowModeCorrectForVr()) {
@@ -924,15 +986,18 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
return true;
}
+ private boolean cancelStartupAnimationIfNeeded() {
+ if (!mNeedsAnimationCancel) return false;
+ mCancellingEntryAnimation = true;
+ Bundle options = ActivityOptions.makeCustomAnimation(mActivity, 0, 0).toBundle();
+ mActivity.startActivity(new Intent(mActivity, VrCancelAnimationActivity.class), options);
+ mNeedsAnimationCancel = false;
+ return true;
+ }
+
private void onResume() {
- if (mNeedsAnimationCancel) {
- mCancellingEntryAnimation = true;
- Bundle options = ActivityOptions.makeCustomAnimation(mActivity, 0, 0).toBundle();
- mActivity.startActivity(
- new Intent(mActivity, VrCancelAnimationActivity.class), options);
- mNeedsAnimationCancel = false;
- return;
- }
+ if (cancelStartupAnimationIfNeeded()) return;
+
mPaused = false;
updateVrSupportLevel();
@@ -1139,7 +1204,7 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
// Ensure we can't asynchronously enter VR after trying to exit it.
mEnterVrHandler.removeCallbacksAndMessages(null);
mDonSucceeded = false;
- removeOverlayView();
+ removeBlackOverlayView();
mVrClassesWrapper.setVrModeEnabled(mActivity, false);
restoreWindowMode();
}
@@ -1369,23 +1434,6 @@ public class VrShellDelegate implements ApplicationStatus.ActivityStateListener,
mRestoreSystemUiVisibilityFlag = -1;
}
- private void addOverlayView() {
- if (mOverlayView != null) return;
- FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
- WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
- FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView();
- mOverlayView = new View(mActivity);
- mOverlayView.setBackgroundColor(Color.BLACK);
- decor.addView(mOverlayView, -1, params);
- }
-
- private void removeOverlayView() {
- if (mOverlayView == null) return;
- FrameLayout decor = (FrameLayout) sInstance.mActivity.getWindow().getDecorView();
- decor.removeView(mOverlayView);
- mOverlayView = null;
- }
-
/**
* Clean up VrShell, and associated native objects.
*/

Powered by Google App Engine
This is Rietveld 408576698