| 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 9b2453af06c64873eef5cc97c17a0cc1c22064c0..8e3a6b3baead5999469e0e736a035f05c86fc1d3 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
|
| @@ -26,12 +26,12 @@ import android.view.ViewGroup.LayoutParams;
|
| import android.view.WindowManager;
|
| import android.widget.FrameLayout;
|
|
|
| +import org.chromium.base.ApplicationStatus;
|
| import org.chromium.base.Log;
|
| import org.chromium.base.VisibleForTesting;
|
| import org.chromium.base.annotations.CalledByNative;
|
| import org.chromium.base.annotations.JNINamespace;
|
| import org.chromium.base.library_loader.LibraryLoader;
|
| -
|
| import org.chromium.chrome.R;
|
| import org.chromium.chrome.browser.ChromeActivity;
|
| import org.chromium.chrome.browser.ChromeFeatureList;
|
| @@ -43,6 +43,7 @@ import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
|
| import org.chromium.chrome.browser.tab.Tab;
|
| import org.chromium.chrome.browser.tabmodel.TabModel;
|
| import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
|
| +import org.chromium.chrome.browser.tabmodel.TabModelSelector;
|
| import org.chromium.chrome.browser.tabmodel.TabModelUtils;
|
|
|
| import java.lang.annotation.Retention;
|
| @@ -90,8 +91,9 @@ public class VrShellDelegate {
|
|
|
| private static final long REENTER_VR_TIMEOUT_MS = 1000;
|
|
|
| - private final ChromeTabbedActivity mActivity;
|
| - private Intent mEnterVRIntent;
|
| + private static VrShellDelegate sInstance;
|
| +
|
| + private final ChromeActivity mActivity;
|
|
|
| @VrSupportLevel
|
| private int mVrSupportLevel;
|
| @@ -101,6 +103,7 @@ public class VrShellDelegate {
|
| private NonPresentingGvrContext mNonPresentingGvrContext;
|
| private VrDaydreamApi mVrDaydreamApi;
|
| private VrCoreVersionChecker mVrCoreVersionChecker;
|
| + private TabModelSelector mTabModelSelector;
|
|
|
| private boolean mInVr;
|
| private boolean mEnteringVr;
|
| @@ -113,78 +116,152 @@ public class VrShellDelegate {
|
| private boolean mListeningForWebVrActivate;
|
| private boolean mListeningForWebVrActivateBeforePause;
|
|
|
| - public VrShellDelegate(ChromeTabbedActivity activity) {
|
| - mActivity = activity;
|
| - mVrClassesWrapper = createVrClassesWrapper();
|
| + /**
|
| + * Called when the native library is first available.
|
| + */
|
| + public static void onNativeLibraryAvailable() {
|
| + nativeOnLibraryAvailable();
|
| }
|
|
|
| /**
|
| - * Updates mVrSupportLevel to the correct value. isVrCoreCompatible might return different value
|
| - * at runtime.
|
| + * @return A helper class for creating VR-specific classes that may not be available at compile
|
| + * time.
|
| */
|
| - // TODO(bshe): Find a place to call this function again, i.e. page refresh or onResume.
|
| - // TODO(mthiesse): Clean this function up, lots of duplicated code.
|
| - private void updateVrSupportLevel() {
|
| - if (mVrClassesWrapper == null || !isVrCoreCompatible()) {
|
| - mVrSupportLevel = VR_NOT_AVAILABLE;
|
| - mEnterVRIntent = null;
|
| + @VisibleForTesting
|
| + public static VrClassesWrapper getVrClassesWrapper() {
|
| + if (sInstance != null) return sInstance.mVrClassesWrapper;
|
| + return createVrClassesWrapper();
|
| + }
|
| +
|
| + @VisibleForTesting
|
| + public static VrShellDelegate getInstanceForTesting() {
|
| + return getInstance();
|
| + }
|
| +
|
| + /**
|
| + * Pauses VR Shell, if it needs to be paused.
|
| + */
|
| + public static void maybePauseVR(ChromeActivity activity) {
|
| + maybeUnregisterDaydreamIntent(activity);
|
| + if (sInstance == null) return;
|
| + if (sInstance.mActivity != activity) {
|
| + assert !sInstance.mInVr;
|
| return;
|
| }
|
| + sInstance.pauseVR();
|
| + }
|
|
|
| - if (mVrDaydreamApi == null) {
|
| - mVrDaydreamApi = mVrClassesWrapper.createVrDaydreamApi();
|
| - }
|
| -
|
| - // Check cardboard support for non-daydream devices.
|
| - if (!mVrDaydreamApi.isDaydreamReadyDevice()) {
|
| - // Supported Build version is determined by the webvr cardboard support feature.
|
| - // Default is KITKAT unless specified via server side finch config.
|
| - if (Build.VERSION.SDK_INT < ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
|
| - ChromeFeatureList.WEBVR_CARDBOARD_SUPPORT,
|
| - MIN_SDK_VERSION_PARAM_NAME,
|
| - Build.VERSION_CODES.KITKAT)) {
|
| - mVrSupportLevel = VR_NOT_AVAILABLE;
|
| - mEnterVRIntent = null;
|
| - return;
|
| - }
|
| + /**
|
| + * Resumes VR Shell, if it needs to be resumed.
|
| + */
|
| + public static void maybeResumeVR(ChromeActivity activity) {
|
| + maybeRegisterDaydreamIntent(activity);
|
| + if (sInstance == null) return;
|
| + if (sInstance.mActivity != activity) {
|
| + assert !sInstance.mInVr;
|
| + return;
|
| }
|
| + sInstance.resumeVR();
|
| + }
|
| +
|
| + /**
|
| + * Whether or not we are currently in VR.
|
| + */
|
| + public static boolean isInVR() {
|
| + if (sInstance == null) return false;
|
| + return sInstance.mInVr;
|
| + }
|
| +
|
| + /**
|
| + * See {@link ChromeActivity#handleBackPressed}
|
| + * Only handles the back press while in VR.
|
| + */
|
| + public static boolean onBackPressed() {
|
| + if (sInstance == null) return false;
|
| + return sInstance.onBackPressedInternal();
|
| + }
|
|
|
| - if (mEnterVRIntent == null) {
|
| - mEnterVRIntent =
|
| - mVrDaydreamApi.createVrIntent(new ComponentName(mActivity, VR_ACTIVITY_ALIAS));
|
| + /**
|
| + * Enters VR on the current tab if possible.
|
| + */
|
| + public static void enterVRIfNecessary() {
|
| + boolean created_delegate = sInstance == null;
|
| + VrShellDelegate instance = getInstance();
|
| + if (instance == null) return;
|
| + if (instance.enterVRInternal() == ENTER_VR_CANCELLED && created_delegate) {
|
| + instance.destroy();
|
| }
|
| - mVrSupportLevel = mVrDaydreamApi.isDaydreamReadyDevice() ? VR_DAYDREAM : VR_CARDBOARD;
|
| }
|
|
|
| /**
|
| - * Should be called once the native library is loaded so that the native portion of this class
|
| - * can be initialized.
|
| + * Handles a VR intent, entering VR in the process.
|
| */
|
| - public void onNativeLibraryReady() {
|
| - updateVrSupportLevel();
|
| - if (mVrSupportLevel == VR_NOT_AVAILABLE) return;
|
| - mNativeVrShellDelegate = nativeInit();
|
| - Choreographer choreographer = Choreographer.getInstance();
|
| - choreographer.postFrameCallback(new FrameCallback() {
|
| - @Override
|
| - public void doFrame(long frameTimeNanos) {
|
| - Display display = ((WindowManager) mActivity.getSystemService(
|
| - Context.WINDOW_SERVICE)).getDefaultDisplay();
|
| - nativeUpdateVSyncInterval(mNativeVrShellDelegate, frameTimeNanos,
|
| - 1.0d / display.getRefreshRate());
|
| - }
|
| - });
|
| + public static void enterVRFromIntent(Intent intent) {
|
| + assert isDaydreamVrIntent(intent);
|
| + boolean created_delegate = sInstance == null;
|
| + VrShellDelegate instance = getInstance();
|
| + if (instance == null) return;
|
| + if (!instance.enterVRFromIntent() && created_delegate) instance.destroy();
|
| + }
|
| +
|
| + /**
|
| + * Whether or not the intent is a Daydream VR Intent.
|
| + */
|
| + public static boolean isDaydreamVrIntent(Intent intent) {
|
| + if (intent == null || intent.getCategories() == null) return false;
|
| + return intent.getCategories().contains(DAYDREAM_CATEGORY);
|
| + }
|
| +
|
| + /**
|
| + * Handles the result of the exit VR flow (DOFF).
|
| + */
|
| + public static void onExitVRResult(int resultCode) {
|
| + if (sInstance == null) return;
|
| + sInstance.onExitVRResult(resultCode == Activity.RESULT_OK);
|
| + }
|
| +
|
| + public static int getVrSupportLevel(VrDaydreamApi daydreamApi,
|
| + VrCoreVersionChecker versionChecker, Tab tabToShowInfobarIn) {
|
| + if (versionChecker == null || daydreamApi == null
|
| + || !isVrCoreCompatible(versionChecker, tabToShowInfobarIn)) {
|
| + return VR_NOT_AVAILABLE;
|
| + }
|
| +
|
| + if (daydreamApi.isDaydreamReadyDevice()) return VR_DAYDREAM;
|
| +
|
| + // Check cardboard support for non-daydream devices. Supported Build version is determined
|
| + // by the webvr cardboard support feature. Default is KITKAT unless specified via server
|
| + // side finch config.
|
| + if (Build.VERSION.SDK_INT < ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
|
| + ChromeFeatureList.WEBVR_CARDBOARD_SUPPORT,
|
| + MIN_SDK_VERSION_PARAM_NAME,
|
| + Build.VERSION_CODES.KITKAT)) {
|
| + return VR_NOT_AVAILABLE;
|
| + }
|
| +
|
| + return VR_CARDBOARD;
|
| + }
|
| +
|
| + @CalledByNative
|
| + private static VrShellDelegate getInstance() {
|
| + Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
|
| + if (sInstance != null && activity instanceof ChromeTabbedActivity) return sInstance;
|
| + if (!LibraryLoader.isInitialized()) return null;
|
| + // Note that we only support ChromeTabbedActivity for now.
|
| + if (activity == null || !(activity instanceof ChromeTabbedActivity)) return null;
|
| + sInstance = new VrShellDelegate((ChromeActivity) activity);
|
| +
|
| + return sInstance;
|
| }
|
|
|
| @SuppressWarnings("unchecked")
|
| - private VrClassesWrapper createVrClassesWrapper() {
|
| + private static VrClassesWrapper createVrClassesWrapper() {
|
| try {
|
| Class<? extends VrClassesWrapper> vrClassesBuilderClass =
|
| (Class<? extends VrClassesWrapper>) Class.forName(
|
| "org.chromium.chrome.browser.vr_shell.VrClassesWrapperImpl");
|
| - Constructor<?> vrClassesBuilderConstructor =
|
| - vrClassesBuilderClass.getConstructor(ChromeActivity.class);
|
| - return (VrClassesWrapper) vrClassesBuilderConstructor.newInstance(mActivity);
|
| + Constructor<?> vrClassesBuilderConstructor = vrClassesBuilderClass.getConstructor();
|
| + return (VrClassesWrapper) vrClassesBuilderConstructor.newInstance();
|
| } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
| | IllegalArgumentException | InvocationTargetException | NoSuchMethodException e) {
|
| if (!(e instanceof ClassNotFoundException)) {
|
| @@ -194,33 +271,123 @@ public class VrShellDelegate {
|
| }
|
| }
|
|
|
| + private static PendingIntent getEnterVRPendingIntent(
|
| + VrDaydreamApi dayreamApi, Activity activity) {
|
| + return PendingIntent.getActivity(activity, 0,
|
| + dayreamApi.createVrIntent(new ComponentName(activity, VR_ACTIVITY_ALIAS)),
|
| + PendingIntent.FLAG_ONE_SHOT);
|
| + }
|
| +
|
| + private static void maybeRegisterDaydreamIntent(Activity activity) {
|
| + if (sInstance != null) return; // Will be handled in onResume.
|
| + if (!(activity instanceof ChromeTabbedActivity)) return;
|
| + VrClassesWrapper wrapper = createVrClassesWrapper();
|
| + if (wrapper == null) return;
|
| + VrDaydreamApi api = wrapper.createVrDaydreamApi(activity);
|
| + if (api == null) return;
|
| + int vrSupportLevel = getVrSupportLevel(api, wrapper.createVrCoreVersionChecker(), null);
|
| + if (isVrShellEnabled(vrSupportLevel)) registerDaydreamIntent(api, activity);
|
| + }
|
| +
|
| + private static void maybeUnregisterDaydreamIntent(Activity activity) {
|
| + if (sInstance != null) return; // Will be handled in onPause.
|
| + if (!(activity instanceof ChromeTabbedActivity)) return;
|
| + VrClassesWrapper wrapper = createVrClassesWrapper();
|
| + if (wrapper == null) return;
|
| + VrDaydreamApi api = wrapper.createVrDaydreamApi(activity);
|
| + if (api == null) return;
|
| + unregisterDaydreamIntent(api);
|
| + }
|
| +
|
| + /**
|
| + * Registers the Intent to fire after phone inserted into a headset.
|
| + */
|
| + private static void registerDaydreamIntent(VrDaydreamApi dayreamApi, Activity activity) {
|
| + dayreamApi.registerDaydreamIntent(getEnterVRPendingIntent(dayreamApi, activity));
|
| + }
|
| +
|
| + /**
|
| + * Unregisters the Intent which registered by this context if any.
|
| + */
|
| + private static void unregisterDaydreamIntent(VrDaydreamApi dayreamApi) {
|
| + dayreamApi.unregisterDaydreamIntent();
|
| + }
|
| +
|
| + /**
|
| + * @return Whether or not VR Shell is currently enabled.
|
| + */
|
| + private static boolean isVrShellEnabled(int vrSupportLevel) {
|
| + // Only enable ChromeVR (VrShell) on Daydream devices as it currently needs a Daydream
|
| + // controller.
|
| + if (vrSupportLevel != VR_DAYDREAM) return false;
|
| + return ChromeFeatureList.isEnabled(ChromeFeatureList.VR_SHELL);
|
| + }
|
| +
|
| + private VrShellDelegate(ChromeActivity activity) {
|
| + mActivity = activity;
|
| + mVrClassesWrapper = createVrClassesWrapper();
|
| + updateVrSupportLevel();
|
| + mNativeVrShellDelegate = nativeInit();
|
| + Choreographer choreographer = Choreographer.getInstance();
|
| + choreographer.postFrameCallback(new FrameCallback() {
|
| + @Override
|
| + public void doFrame(long frameTimeNanos) {
|
| + Display display =
|
| + ((WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE))
|
| + .getDefaultDisplay();
|
| + nativeUpdateVSyncInterval(
|
| + mNativeVrShellDelegate, frameTimeNanos, 1.0d / display.getRefreshRate());
|
| + }
|
| + });
|
| + }
|
| +
|
| + /**
|
| + * Updates mVrSupportLevel to the correct value. isVrCoreCompatible might return different value
|
| + * at runtime.
|
| + */
|
| + // TODO(bshe): Find a place to call this function again, i.e. page refresh or onResume.
|
| + private void updateVrSupportLevel() {
|
| + if (mVrClassesWrapper == null) {
|
| + mVrSupportLevel = VR_NOT_AVAILABLE;
|
| + return;
|
| + }
|
| + if (mVrCoreVersionChecker == null) {
|
| + mVrCoreVersionChecker = mVrClassesWrapper.createVrCoreVersionChecker();
|
| + }
|
| + if (mVrDaydreamApi == null) {
|
| + mVrDaydreamApi = mVrClassesWrapper.createVrDaydreamApi(mActivity);
|
| + }
|
| + mVrSupportLevel = getVrSupportLevel(
|
| + mVrDaydreamApi, mVrCoreVersionChecker, mActivity.getActivityTab());
|
| + }
|
| +
|
| /**
|
| * Handle a VR intent, entering VR in the process unless we're unable to.
|
| */
|
| - public void enterVRFromIntent(Intent intent) {
|
| + private boolean enterVRFromIntent() {
|
| // Vr Intent is only used on Daydream devices.
|
| - if (mVrSupportLevel != VR_DAYDREAM) return;
|
| - assert isDaydreamVrIntent(intent);
|
| + if (mVrSupportLevel != VR_DAYDREAM) return false;
|
| if (mListeningForWebVrActivateBeforePause && !mRequestedWebVR) {
|
| nativeDisplayActivate(mNativeVrShellDelegate);
|
| - return;
|
| + return false;
|
| }
|
| // Normally, if the active page doesn't have a vrdisplayactivate listener, and WebVR was not
|
| // presenting and VrShell was not enabled, we shouldn't enter VR and Daydream Homescreen
|
| // should show after DON flow. But due to a failure in unregisterDaydreamIntent, we still
|
| // try to enterVR. Here we detect this case and force switch to Daydream Homescreen.
|
| - if (!mListeningForWebVrActivateBeforePause && !mRequestedWebVR && !isVrShellEnabled()) {
|
| + if (!mListeningForWebVrActivateBeforePause && !mRequestedWebVR
|
| + && !isVrShellEnabled(mVrSupportLevel)) {
|
| mVrDaydreamApi.launchVrHomescreen();
|
| - return;
|
| + return false;
|
| }
|
|
|
| if (mInVr) {
|
| setEnterVRResult(true);
|
| - return;
|
| + return false;
|
| }
|
| if (!canEnterVR(mActivity.getActivityTab())) {
|
| setEnterVRResult(false);
|
| - return;
|
| + return false;
|
| }
|
| if (mPaused) {
|
| // We can't enter VR before the application resumes, or we encounter bizarre crashes
|
| @@ -230,6 +397,7 @@ public class VrShellDelegate {
|
| } else {
|
| enterVR();
|
| }
|
| + return true;
|
| }
|
|
|
| private void prepareToEnterVR() {
|
| @@ -261,7 +429,7 @@ public class VrShellDelegate {
|
| setEnterVRResult(false);
|
| return;
|
| }
|
| - mVrClassesWrapper.setVrModeEnabled(true);
|
| + mVrClassesWrapper.setVrModeEnabled(mActivity, true);
|
| mInVr = true;
|
|
|
| addVrViews();
|
| @@ -276,7 +444,7 @@ public class VrShellDelegate {
|
| private void setEnterVRResult(boolean success) {
|
| if (mRequestedWebVR) nativeSetPresentResult(mNativeVrShellDelegate, success);
|
| if (!success && !mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent())) {
|
| - mVrClassesWrapper.setVrModeEnabled(false);
|
| + mVrClassesWrapper.setVrModeEnabled(mActivity, false);
|
| }
|
| mRequestedWebVR = false;
|
| }
|
| @@ -285,10 +453,10 @@ public class VrShellDelegate {
|
| 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 (mVrSupportLevel == VR_NOT_AVAILABLE || mNativeVrShellDelegate == 0
|
| - || (!isVrShellEnabled() && !(mRequestedWebVR || mListeningForWebVrActivate))) {
|
| + if (mVrSupportLevel == VR_NOT_AVAILABLE || mNativeVrShellDelegate == 0) return false;
|
| + // If vr shell is not enabled and this is not a web vr request, then return false.
|
| + if (!isVrShellEnabled(mVrSupportLevel)
|
| + && !(mRequestedWebVR || mListeningForWebVrActivate)) {
|
| return false;
|
| }
|
| // TODO(mthiesse): When we have VR UI for opening new tabs, etc., allow VR Shell to be
|
| @@ -313,7 +481,7 @@ public class VrShellDelegate {
|
| // ask them to when we call DaydreamApi#launchInVr. As a temporary hack, remember locally
|
| // that we want to enter webVR.
|
| mRequestedWebVR = true;
|
| - switch (enterVRIfNecessary()) {
|
| + switch (enterVRInternal()) {
|
| case ENTER_VR_NOT_NECESSARY:
|
| mVrShell.setWebVrModeEnabled(true);
|
| nativeSetPresentResult(mNativeVrShellDelegate, true);
|
| @@ -338,7 +506,7 @@ public class VrShellDelegate {
|
| * Enters VR Shell if necessary, displaying browser UI and tab contents in VR.
|
| */
|
| @EnterVRResult
|
| - public int enterVRIfNecessary() {
|
| + private int enterVRInternal() {
|
| // Update VR support level as it can change at runtime
|
| updateVrSupportLevel();
|
| if (mVrSupportLevel == VR_NOT_AVAILABLE) return ENTER_VR_CANCELLED;
|
| @@ -350,7 +518,9 @@ public class VrShellDelegate {
|
| // due to the lack of support for unexported activities.
|
| enterVR();
|
| } else {
|
| - if (!mVrDaydreamApi.launchInVr(getPendingEnterVRIntent())) return ENTER_VR_CANCELLED;
|
| + if (!mVrDaydreamApi.launchInVr(getEnterVRPendingIntent(mVrDaydreamApi, mActivity))) {
|
| + return ENTER_VR_CANCELLED;
|
| + }
|
| }
|
| return ENTER_VR_REQUESTED;
|
| }
|
| @@ -367,20 +537,18 @@ public class VrShellDelegate {
|
| // TODO(bajones): Once VR Shell can be invoked outside of WebVR this
|
| // should no longer exit the shell outright. Need a way to determine
|
| // how VrShell was created.
|
| - shutdownVR(false /* isPausing */, !isVrShellEnabled() /* showTransition */);
|
| + shutdownVR(
|
| + false /* isPausing */, !isVrShellEnabled(mVrSupportLevel) /* showTransition */);
|
| }
|
| return true;
|
| }
|
|
|
| - /**
|
| - * Resumes VR Shell.
|
| - */
|
| - public void maybeResumeVR() {
|
| + private void resumeVR() {
|
| mPaused = false;
|
| if (mVrSupportLevel == VR_NOT_AVAILABLE) return;
|
| if (mVrSupportLevel == VR_DAYDREAM
|
| - && (isVrShellEnabled() || mListeningForWebVrActivateBeforePause)) {
|
| - registerDaydreamIntent();
|
| + && (isVrShellEnabled(mVrSupportLevel) || mListeningForWebVrActivateBeforePause)) {
|
| + registerDaydreamIntent(mVrDaydreamApi, mActivity);
|
| }
|
|
|
| if (mEnteringVr) {
|
| @@ -411,19 +579,16 @@ public class VrShellDelegate {
|
| }
|
| } else if (mVrSupportLevel == VR_DAYDREAM && mVrDaydreamApi.isDaydreamCurrentViewer()
|
| && mLastVRExit + REENTER_VR_TIMEOUT_MS > SystemClock.uptimeMillis()) {
|
| - enterVRIfNecessary();
|
| + enterVRInternal();
|
| }
|
| }
|
|
|
| - /**
|
| - * Pauses VR Shell.
|
| - */
|
| - public void maybePauseVR() {
|
| + private void pauseVR() {
|
| mPaused = true;
|
| if (mVrSupportLevel == VR_NOT_AVAILABLE) return;
|
|
|
| if (mVrSupportLevel == VR_DAYDREAM) {
|
| - unregisterDaydreamIntent();
|
| + unregisterDaydreamIntent(mVrDaydreamApi);
|
|
|
| // When the active web page has a vrdisplayactivate event handler,
|
| // mListeningForWebVrActivate should be set to true, which means a vrdisplayactive event
|
| @@ -442,56 +607,31 @@ public class VrShellDelegate {
|
| shutdownVR(true /* isPausing */, false /* showTransition */);
|
| }
|
|
|
| - /**
|
| - * See {@link ChromeActivity#handleBackPressed}
|
| - */
|
| - public boolean onBackPressed() {
|
| + private boolean onBackPressedInternal() {
|
| if (mVrSupportLevel == VR_NOT_AVAILABLE) return false;
|
| if (!mInVr) return false;
|
| shutdownVR(false /* isPausing */, false /* showTransition */);
|
| return true;
|
| }
|
|
|
| - public void onExitVRResult(int resultCode) {
|
| + private void onExitVRResult(boolean success) {
|
| assert mVrSupportLevel != VR_NOT_AVAILABLE;
|
| - if (resultCode == Activity.RESULT_OK) {
|
| - mVrClassesWrapper.setVrModeEnabled(false);
|
| - } else {
|
| - // For now, we don't handle re-entering VR when exit fails, so keep trying to exit.
|
| - if (!mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent())) {
|
| - mVrClassesWrapper.setVrModeEnabled(false);
|
| - }
|
| - }
|
| - }
|
| -
|
| - 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() {
|
| - mVrDaydreamApi.registerDaydreamIntent(getPendingEnterVRIntent());
|
| - }
|
| -
|
| - /**
|
| - * Unregisters the Intent which registered by this context if any.
|
| - */
|
| - private void unregisterDaydreamIntent() {
|
| - mVrDaydreamApi.unregisterDaydreamIntent();
|
| + // For now, we don't handle re-entering VR when exit fails, so keep trying to exit.
|
| + if (!success && sInstance.mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent())) return;
|
| + sInstance.mVrClassesWrapper.setVrModeEnabled(sInstance.mActivity, false);
|
| }
|
|
|
| @CalledByNative
|
| private long createNonPresentingNativeContext() {
|
| if (mVrClassesWrapper == null) return 0;
|
| - mNonPresentingGvrContext = mVrClassesWrapper.createNonPresentingGvrContext();
|
| + mNonPresentingGvrContext = mVrClassesWrapper.createNonPresentingGvrContext(mActivity);
|
| if (mNonPresentingGvrContext == null) return 0;
|
| return mNonPresentingGvrContext.getNativeGvrContext();
|
| }
|
|
|
| @CalledByNative
|
| private void shutdownNonPresentingNativeContext() {
|
| + if (mNonPresentingGvrContext == null) return;
|
| mNonPresentingGvrContext.shutdown();
|
| mNonPresentingGvrContext = null;
|
| }
|
| @@ -503,9 +643,9 @@ public class VrShellDelegate {
|
| if (mVrSupportLevel != VR_DAYDREAM) return;
|
| mListeningForWebVrActivate = listening;
|
| if (listening) {
|
| - registerDaydreamIntent();
|
| + registerDaydreamIntent(mVrDaydreamApi, mActivity);
|
| } else {
|
| - unregisterDaydreamIntent();
|
| + unregisterDaydreamIntent(mVrDaydreamApi);
|
| }
|
| }
|
|
|
| @@ -519,10 +659,10 @@ public class VrShellDelegate {
|
| boolean transition = mVrSupportLevel == VR_DAYDREAM && showTransition;
|
| if (!isPausing) {
|
| if (!transition || !mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent())) {
|
| - mVrClassesWrapper.setVrModeEnabled(false);
|
| + mVrClassesWrapper.setVrModeEnabled(mActivity, false);
|
| }
|
| } else {
|
| - mVrClassesWrapper.setVrModeEnabled(false);
|
| + mVrClassesWrapper.setVrModeEnabled(mActivity, false);
|
| mLastVRExit = SystemClock.uptimeMillis();
|
| }
|
| if (mRestoreOrientation != null) mActivity.setRequestedOrientation(mRestoreOrientation);
|
| @@ -534,17 +674,13 @@ public class VrShellDelegate {
|
| mActivity.getFullscreenManager().setPositionsForTabToNonFullscreen();
|
| }
|
|
|
| - private boolean isVrCoreCompatible() {
|
| - assert mVrClassesWrapper != null;
|
| - if (mVrCoreVersionChecker == null) {
|
| - mVrCoreVersionChecker = mVrClassesWrapper.createVrCoreVersionChecker();
|
| - }
|
| -
|
| + private static boolean isVrCoreCompatible(
|
| + VrCoreVersionChecker versionChecker, Tab tabToShowInfobarIn) {
|
| return verifyOrUpdateVrServices(
|
| - mVrCoreVersionChecker.getVrCoreCompatibility(), mActivity.getActivityTab());
|
| + versionChecker.getVrCoreCompatibility(), tabToShowInfobarIn);
|
| }
|
|
|
| - private boolean verifyOrUpdateVrServices(int vrCoreCompatibility, Tab tab) {
|
| + private static boolean verifyOrUpdateVrServices(int vrCoreCompatibility, Tab tab) {
|
| if (vrCoreCompatibility == VrCoreVersionChecker.VR_READY) {
|
| return true;
|
| }
|
| @@ -558,16 +694,16 @@ public class VrShellDelegate {
|
| Build.VERSION_CODES.KITKAT)) {
|
| return false;
|
| }
|
| -
|
| + final Activity activity = tab.getActivity();
|
| String infobarText;
|
| String buttonText;
|
| if (vrCoreCompatibility == VrCoreVersionChecker.VR_NOT_AVAILABLE) {
|
| // Supported, but not installed. Ask user to install instead of upgrade.
|
| - infobarText = mActivity.getString(R.string.vr_services_check_infobar_install_text);
|
| - buttonText = mActivity.getString(R.string.vr_services_check_infobar_install_button);
|
| + infobarText = activity.getString(R.string.vr_services_check_infobar_install_text);
|
| + buttonText = activity.getString(R.string.vr_services_check_infobar_install_button);
|
| } else if (vrCoreCompatibility == VrCoreVersionChecker.VR_OUT_OF_DATE) {
|
| - infobarText = mActivity.getString(R.string.vr_services_check_infobar_update_text);
|
| - buttonText = mActivity.getString(R.string.vr_services_check_infobar_update_button);
|
| + infobarText = activity.getString(R.string.vr_services_check_infobar_update_text);
|
| + buttonText = activity.getString(R.string.vr_services_check_infobar_update_button);
|
| } else {
|
| Log.e(TAG, "Unknown VrCore compatibility: " + vrCoreCompatibility);
|
| return false;
|
| @@ -580,7 +716,7 @@ public class VrShellDelegate {
|
|
|
| @Override
|
| public boolean onInfoBarButtonClicked(boolean isPrimary) {
|
| - mActivity.startActivity(new Intent(Intent.ACTION_VIEW,
|
| + activity.startActivity(new Intent(Intent.ACTION_VIEW,
|
| Uri.parse("market://details?id=" + VR_CORE_PACKAGE_ID)));
|
| return false;
|
| }
|
| @@ -592,7 +728,9 @@ public class VrShellDelegate {
|
|
|
| private boolean createVrShell() {
|
| if (mVrClassesWrapper == null) return false;
|
| - mVrShell = mVrClassesWrapper.createVrShell(this, mActivity.getCompositorViewHolder());
|
| + mTabModelSelector = mActivity.getCompositorViewHolder().detachForVR();
|
| + if (mTabModelSelector == null) return false;
|
| + mVrShell = mVrClassesWrapper.createVrShell(mActivity, this, mTabModelSelector);
|
| return mVrShell != null;
|
| }
|
|
|
| @@ -602,11 +740,11 @@ public class VrShellDelegate {
|
| ViewGroup.LayoutParams.MATCH_PARENT,
|
| ViewGroup.LayoutParams.MATCH_PARENT);
|
| decor.addView(mVrShell.getContainer(), params);
|
| - mActivity.setUIVisibilityForVR(View.GONE);
|
| + mActivity.onEnterVR();
|
| }
|
|
|
| private void removeVrViews() {
|
| - mActivity.setUIVisibilityForVR(View.VISIBLE);
|
| + mActivity.onExitVR();
|
| FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView();
|
| decor.removeView(mVrShell.getContainer());
|
| }
|
| @@ -635,39 +773,15 @@ public class VrShellDelegate {
|
| /**
|
| * Clean up VrShell, and associated native objects.
|
| */
|
| - public void destroyVrShell() {
|
| + private void destroyVrShell() {
|
| if (mVrShell != null) {
|
| mVrShell.teardown();
|
| mVrShell = null;
|
| + mActivity.getCompositorViewHolder().onExitVR(mTabModelSelector);
|
| }
|
| }
|
|
|
| /**
|
| - * Whether or not the intent is a Daydream VR Intent.
|
| - */
|
| - public boolean isDaydreamVrIntent(Intent intent) {
|
| - if (intent == null || intent.getCategories() == null) return false;
|
| - return intent.getCategories().contains(DAYDREAM_CATEGORY);
|
| - }
|
| -
|
| - /**
|
| - * Whether or not we are currently in VR.
|
| - */
|
| - public boolean isInVR() {
|
| - return mInVr;
|
| - }
|
| -
|
| - /**
|
| - * @return Whether or not VR Shell is currently enabled.
|
| - */
|
| - private boolean isVrShellEnabled() {
|
| - // Only enable ChromeVR (VrShell) on Daydream devices as it currently needs a Daydream
|
| - // controller.
|
| - if (mVrSupportLevel != VR_DAYDREAM) return false;
|
| - return ChromeFeatureList.isEnabled(ChromeFeatureList.VR_SHELL);
|
| - }
|
| -
|
| - /**
|
| * @param api The VrDaydreamApi object this delegate will use instead of the default one
|
| */
|
| @VisibleForTesting
|
| @@ -702,11 +816,19 @@ public class VrShellDelegate {
|
| UrlConstants.NTP_URL, TabLaunchType.FROM_CHROME_UI);
|
| }
|
|
|
| + private void destroy() {
|
| + if (sInstance == null) return;
|
| + if (mNativeVrShellDelegate != 0) nativeDestroy(mNativeVrShellDelegate);
|
| + sInstance = null;
|
| + }
|
| +
|
| private native long nativeInit();
|
| + private static native void nativeOnLibraryAvailable();
|
| private native void nativeSetPresentResult(long nativeVrShellDelegate, boolean result);
|
| private native void nativeDisplayActivate(long nativeVrShellDelegate);
|
| private native void nativeUpdateVSyncInterval(long nativeVrShellDelegate, long timebaseNanos,
|
| double intervalSeconds);
|
| private native void nativeOnPause(long nativeVrShellDelegate);
|
| private native void nativeOnResume(long nativeVrShellDelegate);
|
| + private native void nativeDestroy(long nativeVrShellDelegate);
|
| }
|
|
|