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); |
} |