| 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 bea4861e16ca4a7407a987c0709897a0757c474d..ed98793eb158000bb485305bc3d2d4ab7ca7c919 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
|
| @@ -11,6 +11,7 @@ import android.content.Intent;
|
| import android.content.pm.ActivityInfo;
|
| import android.os.StrictMode;
|
| import android.os.SystemClock;
|
| +import android.support.annotation.IntDef;
|
| import android.view.View;
|
| import android.view.ViewGroup;
|
| import android.view.ViewGroup.LayoutParams;
|
| @@ -28,6 +29,8 @@ import org.chromium.chrome.browser.tab.Tab;
|
| import org.chromium.chrome.browser.tab.TabObserver;
|
| import org.chromium.content_public.common.BrowserControlsState;
|
|
|
| +import java.lang.annotation.Retention;
|
| +import java.lang.annotation.RetentionPolicy;
|
| import java.lang.reflect.Constructor;
|
| import java.lang.reflect.InvocationTargetException;
|
|
|
| @@ -40,6 +43,13 @@ public class VrShellDelegate {
|
| // Pseudo-random number to avoid request id collisions.
|
| public static final int EXIT_VR_RESULT = 721251;
|
|
|
| + public static final int ENTER_VR_NOT_NECESSARY = 0;
|
| + public static final int ENTER_VR_CANCELLED = 1;
|
| + public static final int ENTER_VR_REQUESTED = 2;
|
| + @Retention(RetentionPolicy.SOURCE)
|
| + @IntDef({ENTER_VR_NOT_NECESSARY, ENTER_VR_CANCELLED, ENTER_VR_REQUESTED})
|
| + public @interface EnterVRResult {}
|
| +
|
| // TODO(bshe): These should be replaced by string provided by NDK. Currently, it only available
|
| // in SDK and we don't want add dependency to SDK just to get these strings.
|
| private static final String DAYDREAM_VR_EXTRA = "android.intent.extra.VR_LAUNCH";
|
| @@ -48,16 +58,12 @@ public class VrShellDelegate {
|
|
|
| private static final String VR_ACTIVITY_ALIAS =
|
| "org.chromium.chrome.browser.VRChromeTabbedActivity";
|
| - private static final String DAYDREAM_DON_TYPE = "DAYDREAM_DON_TYPE";
|
| -
|
| - private static final int DAYDREAM_DON_TYPE_VR_SHELL = 0;
|
| - private static final int DAYDREAM_DON_TYPE_WEBVR = 1;
|
| - private static final int DAYDREAM_DON_TYPE_AUTO = 2;
|
|
|
| private static final long REENTER_VR_TIMEOUT_MS = 1000;
|
|
|
| private final ChromeTabbedActivity mActivity;
|
| private final TabObserver mTabObserver;
|
| + private final Intent mEnterVRIntent;
|
|
|
| private boolean mVrAvailable;
|
| private Boolean mVrShellEnabled;
|
| @@ -80,8 +86,13 @@ public class VrShellDelegate {
|
|
|
| public VrShellDelegate(ChromeTabbedActivity activity) {
|
| mActivity = activity;
|
| - mVrAvailable = maybeFindVrClasses() && isVrCoreCompatible();
|
| - createVrDaydreamApi();
|
| + mVrAvailable = maybeFindVrClasses() && isVrCoreCompatible() && createVrDaydreamApi();
|
| + if (mVrAvailable) {
|
| + mEnterVRIntent = mVrDaydreamApi.createVrIntent(
|
| + new ComponentName(mActivity, VR_ACTIVITY_ALIAS));
|
| + } else {
|
| + mEnterVRIntent = null;
|
| + }
|
| mTabObserver = new EmptyTabObserver() {
|
| @Override
|
| public void onContentChanged(Tab tab) {
|
| @@ -105,9 +116,8 @@ public class VrShellDelegate {
|
| * class can be initialized.
|
| */
|
| public void onNativeLibraryReady() {
|
| - if (mVrAvailable) {
|
| - mNativeVrShellDelegate = nativeInit();
|
| - }
|
| + if (!mVrAvailable) return;
|
| + mNativeVrShellDelegate = nativeInit();
|
| }
|
|
|
| @SuppressWarnings("unchecked")
|
| @@ -135,28 +145,28 @@ public class VrShellDelegate {
|
| /**
|
| * Handle a VR intent, entering VR in the process.
|
| */
|
| - public boolean enterVRFromIntent(Intent intent) {
|
| + public void enterVRFromIntent(Intent intent) {
|
| + if (!mVrAvailable) return;
|
| assert isVrIntent(intent);
|
| - int transitionType = intent.getIntExtra(DAYDREAM_DON_TYPE, DAYDREAM_DON_TYPE_VR_SHELL);
|
| - if (!isVrShellEnabled()) {
|
| - assert transitionType != DAYDREAM_DON_TYPE_VR_SHELL;
|
| + if (enterVR()) {
|
| + if (mRequestedWebVR) {
|
| + nativeSetPresentResult(mNativeVrShellDelegate, true);
|
| + mVrShell.setWebVrModeEnabled(true);
|
| + }
|
| + } else {
|
| + if (mRequestedWebVR) nativeSetPresentResult(mNativeVrShellDelegate, false);
|
| + mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent());
|
| }
|
|
|
| - boolean inWebVR = transitionType == DAYDREAM_DON_TYPE_WEBVR
|
| - || (transitionType == DAYDREAM_DON_TYPE_AUTO
|
| - && (!isVrShellEnabled() || mRequestedWebVR));
|
| mRequestedWebVR = false;
|
| - Tab tab = mActivity.getActivityTab();
|
| - if (!canEnterVR(inWebVR, tab)) return false;
|
| + }
|
|
|
| - // TODO(mthiesse): We should handle switching between webVR and VR Shell mode through
|
| - // intents.
|
| + private boolean enterVR() {
|
| if (mInVr) return true;
|
| -
|
| mVrDaydreamApi.setVrModeEnabled(true);
|
|
|
| - mTab = tab;
|
| - mTab.addObserver(mTabObserver);
|
| + Tab tab = mActivity.getActivityTab();
|
| + if (!canEnterVR(tab)) return false;
|
|
|
| mRestoreOrientation = mActivity.getRequestedOrientation();
|
| mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
| @@ -164,10 +174,12 @@ public class VrShellDelegate {
|
| mActivity.setRequestedOrientation(mRestoreOrientation);
|
| return false;
|
| }
|
| + mInVr = true;
|
| + mTab = tab;
|
| + mTab.addObserver(mTabObserver);
|
| addVrViews();
|
| setupVrModeWindowFlags();
|
| mVrShell.initializeNative(mTab, this);
|
| - if (inWebVR) mVrShell.setWebVrModeEnabled(true);
|
| mVrShell.setCloseButtonListener(new Runnable() {
|
| @Override
|
| public void run() {
|
| @@ -177,18 +189,18 @@ public class VrShellDelegate {
|
| // onResume needs to be called on GvrLayout after initialization to make sure DON flow work
|
| // properly.
|
| mVrShell.resume();
|
| - mInVr = true;
|
| mTab.updateFullscreenEnabledState();
|
| return true;
|
| }
|
|
|
| - private boolean canEnterVR(boolean inWebVR, Tab tab) {
|
| + private boolean canEnterVR(Tab tab) {
|
| if (!LibraryLoader.isInitialized()) {
|
| return false;
|
| }
|
| // If vr isn't in the build, or we haven't initialized yet, or vr shell is not enabled and
|
| // this is not a web vr request, then return immediately.
|
| - if (!mVrAvailable || mNativeVrShellDelegate == 0 || (!isVrShellEnabled() && !inWebVR)) {
|
| + if (!mVrAvailable || mNativeVrShellDelegate == 0
|
| + || (!isVrShellEnabled() && !mRequestedWebVR)) {
|
| return false;
|
| }
|
| // TODO(mthiesse): When we have VR UI for opening new tabs, etc., allow VR Shell to be
|
| @@ -204,28 +216,38 @@ public class VrShellDelegate {
|
| return true;
|
| }
|
|
|
| - /**
|
| - * Enters VR Shell, displaying browser UI and tab contents in VR.
|
| - *
|
| - * @param inWebVR If true should begin displaying WebVR content rather than the VrShell UI.
|
| - */
|
| @CalledByNative
|
| - public void enterVRIfNecessary(boolean inWebVR) {
|
| - if (mInVr) {
|
| - if (inWebVR) mVrShell.setWebVrModeEnabled(true);
|
| - return;
|
| - }
|
| - if (!canEnterVR(inWebVR, mActivity.getActivityTab())) return;
|
| -
|
| - // TODO(mthiesse): There's a GVR bug where they're not calling us back with the intent we
|
| - // ask them to when we call DaydreamApi#launchInVr. As a temporary hack, remember locally
|
| - // that we want to enter webVR.
|
| + private void presentRequested(boolean inWebVR) {
|
| + // TODO(mthiesse): There's a GVR bug where they're not calling us back with the
|
| + // intent we ask them to when we call DaydreamApi#launchInVr. As a temporary hack,
|
| + // remember locally that we want to enter webVR.
|
| mRequestedWebVR = inWebVR;
|
| - Intent intent = createDaydreamIntent(
|
| - inWebVR ? DAYDREAM_DON_TYPE_WEBVR : DAYDREAM_DON_TYPE_VR_SHELL);
|
| + switch (enterVRIfNecessary()) {
|
| + case ENTER_VR_NOT_NECESSARY:
|
| + mVrShell.setWebVrModeEnabled(true);
|
| + nativeSetPresentResult(mNativeVrShellDelegate, true);
|
| + mRequestedWebVR = false;
|
| + break;
|
| + case ENTER_VR_CANCELLED:
|
| + nativeSetPresentResult(mNativeVrShellDelegate, false);
|
| + mRequestedWebVR = false;
|
| + break;
|
| + case ENTER_VR_REQUESTED:
|
| + break;
|
| + }
|
| + }
|
|
|
| - mVrDaydreamApi.launchInVr(
|
| - PendingIntent.getActivity(mActivity, 0, intent, PendingIntent.FLAG_ONE_SHOT));
|
| + /**
|
| + * Enters VR Shell if necessary, displaying browser UI and tab contents in VR.
|
| + */
|
| + @EnterVRResult
|
| + public int enterVRIfNecessary() {
|
| + if (!mVrAvailable) return ENTER_VR_CANCELLED;
|
| + if (mInVr) return ENTER_VR_NOT_NECESSARY;
|
| + if (!canEnterVR(mActivity.getActivityTab())) return ENTER_VR_CANCELLED;
|
| +
|
| + mVrDaydreamApi.launchInVr(getPendingEnterVRIntent());
|
| + return ENTER_VR_REQUESTED;
|
| }
|
|
|
| @CalledByNative
|
| @@ -243,9 +265,18 @@ public class VrShellDelegate {
|
| * Resumes VR Shell.
|
| */
|
| public void maybeResumeVR() {
|
| + if (!mVrAvailable) return;
|
| + // TODO(mthiesse): Register the intent when on a page that supports WebVR, even if VrShell
|
| + // isn't enabled.
|
| if (isVrShellEnabled()) {
|
| registerDaydreamIntent();
|
| }
|
| + // If this is still set, it means the user backed out of the DON flow, and we won't be
|
| + // receiving an intent from daydream.
|
| + if (mRequestedWebVR) {
|
| + nativeSetPresentResult(mNativeVrShellDelegate, false);
|
| + mRequestedWebVR = false;
|
| + }
|
|
|
| // TODO(bshe): Ideally, we do not need two gvr context exist at the same time. We can
|
| // probably shutdown non presenting gvr when presenting and create a new one after exit
|
| @@ -272,7 +303,7 @@ public class VrShellDelegate {
|
| StrictMode.setThreadPolicy(oldPolicy);
|
| }
|
| } else if (mLastVRExit + REENTER_VR_TIMEOUT_MS > SystemClock.uptimeMillis()) {
|
| - enterVRIfNecessary(mRequestedWebVR);
|
| + enterVRIfNecessary();
|
| }
|
| }
|
|
|
| @@ -280,9 +311,8 @@ public class VrShellDelegate {
|
| * Pauses VR Shell.
|
| */
|
| public void maybePauseVR() {
|
| - if (isVrShellEnabled()) {
|
| - unregisterDaydreamIntent();
|
| - }
|
| + if (!mVrAvailable) return;
|
| + unregisterDaydreamIntent();
|
|
|
| if (mNonPresentingGvrContext != null) {
|
| mNonPresentingGvrContext.pause();
|
| @@ -299,12 +329,14 @@ public class VrShellDelegate {
|
| * @return Whether or not we exited VR.
|
| */
|
| public boolean exitVRIfNecessary(boolean returnTo2D) {
|
| + if (!mVrAvailable) return false;
|
| if (!mInVr) return false;
|
| shutdownVR(returnTo2D);
|
| return true;
|
| }
|
|
|
| public void onExitVRResult(int resultCode) {
|
| + assert mVrAvailable;
|
| if (resultCode == Activity.RESULT_OK) {
|
| mVrDaydreamApi.setVrModeEnabled(false);
|
| } else {
|
| @@ -313,33 +345,22 @@ public class VrShellDelegate {
|
| }
|
| }
|
|
|
| - private Intent createDaydreamIntent(int transitionType) {
|
| - if (mVrDaydreamApi == null) return null;
|
| - // TODO(bshe): Ideally, this should go through ChromeLauncherActivity. To avoid polluting
|
| - // metrics, use the VR Activity alias for now.
|
| - Intent intent = mVrDaydreamApi.createVrIntent(
|
| - new ComponentName(mActivity, VR_ACTIVITY_ALIAS));
|
| - intent.putExtra(DAYDREAM_DON_TYPE, transitionType);
|
| - return intent;
|
| + private PendingIntent getPendingEnterVRIntent() {
|
| + return PendingIntent.getActivity(mActivity, 0, mEnterVRIntent, PendingIntent.FLAG_ONE_SHOT);
|
| }
|
|
|
| /**
|
| * Registers the Intent to fire after phone inserted into a headset.
|
| */
|
| private void registerDaydreamIntent() {
|
| - if (mVrDaydreamApi == null) return;
|
| - Intent intent = createDaydreamIntent(DAYDREAM_DON_TYPE_AUTO);
|
| - mVrDaydreamApi.registerDaydreamIntent(
|
| - PendingIntent.getActivity(mActivity, 0, intent, PendingIntent.FLAG_ONE_SHOT));
|
| + mVrDaydreamApi.registerDaydreamIntent(getPendingEnterVRIntent());
|
| }
|
|
|
| /**
|
| * Unregisters the Intent which registered by this context if any.
|
| */
|
| private void unregisterDaydreamIntent() {
|
| - if (mVrDaydreamApi != null) {
|
| - mVrDaydreamApi.unregisterDaydreamIntent();
|
| - }
|
| + mVrDaydreamApi.unregisterDaydreamIntent();
|
| }
|
|
|
| @CalledByNative
|
| @@ -371,6 +392,7 @@ public class VrShellDelegate {
|
| */
|
| private void shutdownVR(boolean returnTo2D) {
|
| if (!mInVr) return;
|
| + mRequestedWebVR = false;
|
| if (returnTo2D) {
|
| mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent());
|
| } else {
|
| @@ -404,22 +426,20 @@ public class VrShellDelegate {
|
| (VrCoreVersionChecker) mVrCoreVersionCheckerConstructor.newInstance();
|
| } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
| | InvocationTargetException | NoSuchMethodException e) {
|
| - Log.e(TAG, "Unable to instantiate VrCoreVersionChecker", e);
|
| + Log.d(TAG, "Unable to instantiate VrCoreVersionChecker", e);
|
| return false;
|
| }
|
| return mVrCoreVersionChecker.isVrCoreCompatible();
|
| }
|
|
|
| private boolean createVrDaydreamApi() {
|
| - if (!mVrAvailable) return false;
|
| -
|
| try {
|
| Constructor<?> vrPrivateApiConstructor =
|
| mVrDaydreamApiClass.getConstructor(Activity.class);
|
| mVrDaydreamApi = (VrDaydreamApi) vrPrivateApiConstructor.newInstance(mActivity);
|
| } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
| - | InvocationTargetException | NoSuchMethodException e) {
|
| - Log.e(TAG, "Unable to instantiate VrDaydreamApi", e);
|
| + | InvocationTargetException | NoSuchMethodException | SecurityException e) {
|
| + Log.d(TAG, "Unable to instantiate VrDaydreamApi", e);
|
| return false;
|
| }
|
| return true;
|
| @@ -521,13 +541,6 @@ public class VrShellDelegate {
|
| }
|
|
|
| /**
|
| - * @return Whether or not VR Shell is currently enabled.
|
| - */
|
| - public boolean isVrInitialized() {
|
| - return mVrDaydreamApi != null;
|
| - }
|
| -
|
| - /**
|
| * @return Pointer to the native VrShellDelegate object.
|
| */
|
| @CalledByNative
|
| @@ -536,4 +549,5 @@ public class VrShellDelegate {
|
| }
|
|
|
| private native long nativeInit();
|
| + private native void nativeSetPresentResult(long nativeVrShellDelegate, boolean result);
|
| }
|
|
|