Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.vr_shell; | 5 package org.chromium.chrome.browser.vr_shell; |
| 6 | 6 |
| 7 import android.app.Activity; | 7 import android.app.Activity; |
| 8 import android.app.PendingIntent; | 8 import android.app.PendingIntent; |
| 9 import android.content.ComponentName; | 9 import android.content.ComponentName; |
| 10 import android.content.Context; | 10 import android.content.Context; |
| 11 import android.content.Intent; | 11 import android.content.Intent; |
| 12 import android.content.pm.ActivityInfo; | 12 import android.content.pm.ActivityInfo; |
| 13 import android.content.res.Configuration; | 13 import android.content.res.Configuration; |
| 14 import android.net.Uri; | 14 import android.net.Uri; |
| 15 import android.os.Build; | 15 import android.os.Build; |
| 16 import android.os.Handler; | 16 import android.os.Handler; |
| 17 import android.os.StrictMode; | 17 import android.os.StrictMode; |
| 18 import android.os.SystemClock; | 18 import android.os.SystemClock; |
| 19 import android.support.annotation.IntDef; | 19 import android.support.annotation.IntDef; |
| 20 import android.view.Choreographer; | 20 import android.view.Choreographer; |
| 21 import android.view.Choreographer.FrameCallback; | 21 import android.view.Choreographer.FrameCallback; |
| 22 import android.view.Display; | 22 import android.view.Display; |
| 23 import android.view.View; | 23 import android.view.View; |
| 24 import android.view.ViewGroup; | 24 import android.view.ViewGroup; |
| 25 import android.view.ViewGroup.LayoutParams; | 25 import android.view.ViewGroup.LayoutParams; |
| 26 import android.view.WindowManager; | 26 import android.view.WindowManager; |
| 27 import android.widget.FrameLayout; | 27 import android.widget.FrameLayout; |
| 28 | 28 |
| 29 import org.chromium.base.ApplicationStatus; | |
| 29 import org.chromium.base.Log; | 30 import org.chromium.base.Log; |
| 30 import org.chromium.base.VisibleForTesting; | 31 import org.chromium.base.VisibleForTesting; |
| 31 import org.chromium.base.annotations.CalledByNative; | 32 import org.chromium.base.annotations.CalledByNative; |
| 32 import org.chromium.base.annotations.JNINamespace; | 33 import org.chromium.base.annotations.JNINamespace; |
| 33 import org.chromium.base.library_loader.LibraryLoader; | 34 import org.chromium.base.library_loader.LibraryLoader; |
| 34 | |
| 35 import org.chromium.chrome.R; | 35 import org.chromium.chrome.R; |
| 36 import org.chromium.chrome.browser.ChromeActivity; | 36 import org.chromium.chrome.browser.ChromeActivity; |
| 37 import org.chromium.chrome.browser.ChromeFeatureList; | 37 import org.chromium.chrome.browser.ChromeFeatureList; |
| 38 import org.chromium.chrome.browser.ChromeTabbedActivity; | 38 import org.chromium.chrome.browser.ChromeTabbedActivity; |
| 39 import org.chromium.chrome.browser.infobar.InfoBarIdentifier; | 39 import org.chromium.chrome.browser.infobar.InfoBarIdentifier; |
| 40 import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder; | 40 import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder; |
| 41 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; | 41 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; |
| 42 import org.chromium.chrome.browser.tab.Tab; | 42 import org.chromium.chrome.browser.tab.Tab; |
| 43 import org.chromium.chrome.browser.tabmodel.TabModel; | 43 import org.chromium.chrome.browser.tabmodel.TabModel; |
| 44 import org.chromium.chrome.browser.tabmodel.TabModelSelector; | |
| 44 import org.chromium.chrome.browser.tabmodel.TabModelUtils; | 45 import org.chromium.chrome.browser.tabmodel.TabModelUtils; |
| 45 | 46 |
| 46 import java.lang.annotation.Retention; | 47 import java.lang.annotation.Retention; |
| 47 import java.lang.annotation.RetentionPolicy; | 48 import java.lang.annotation.RetentionPolicy; |
| 48 import java.lang.reflect.Constructor; | 49 import java.lang.reflect.Constructor; |
| 49 import java.lang.reflect.InvocationTargetException; | 50 import java.lang.reflect.InvocationTargetException; |
| 50 | 51 |
| 51 /** | 52 /** |
| 52 * Manages interactions with the VR Shell. | 53 * Manages interactions with the VR Shell. |
| 53 */ | 54 */ |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 81 | 82 |
| 82 private static final String MIN_SDK_VERSION_PARAM_NAME = "min_sdk_version"; | 83 private static final String MIN_SDK_VERSION_PARAM_NAME = "min_sdk_version"; |
| 83 | 84 |
| 84 private static final String VR_ACTIVITY_ALIAS = | 85 private static final String VR_ACTIVITY_ALIAS = |
| 85 "org.chromium.chrome.browser.VRChromeTabbedActivity"; | 86 "org.chromium.chrome.browser.VRChromeTabbedActivity"; |
| 86 | 87 |
| 87 private static final String VR_CORE_PACKAGE_ID = "com.google.vr.vrcore"; | 88 private static final String VR_CORE_PACKAGE_ID = "com.google.vr.vrcore"; |
| 88 | 89 |
| 89 private static final long REENTER_VR_TIMEOUT_MS = 1000; | 90 private static final long REENTER_VR_TIMEOUT_MS = 1000; |
| 90 | 91 |
| 91 private final ChromeTabbedActivity mActivity; | 92 private static VrShellDelegate sInstance; |
| 92 private Intent mEnterVRIntent; | 93 |
| 94 private final ChromeActivity mActivity; | |
| 93 | 95 |
| 94 @VrSupportLevel | 96 @VrSupportLevel |
| 95 private int mVrSupportLevel; | 97 private int mVrSupportLevel; |
| 96 | 98 |
| 97 private final VrClassesWrapper mVrClassesWrapper; | 99 private final VrClassesWrapper mVrClassesWrapper; |
| 98 private VrShell mVrShell; | 100 private VrShell mVrShell; |
| 99 private NonPresentingGvrContext mNonPresentingGvrContext; | 101 private NonPresentingGvrContext mNonPresentingGvrContext; |
| 100 private VrDaydreamApi mVrDaydreamApi; | 102 private VrDaydreamApi mVrDaydreamApi; |
| 101 private VrCoreVersionChecker mVrCoreVersionChecker; | 103 private VrCoreVersionChecker mVrCoreVersionChecker; |
| 104 private TabModelSelector mTabModelSelector; | |
| 102 | 105 |
| 103 private boolean mInVr; | 106 private boolean mInVr; |
| 104 private boolean mEnteringVr; | 107 private boolean mEnteringVr; |
| 105 private boolean mPaused; | 108 private boolean mPaused; |
| 106 private int mRestoreSystemUiVisibilityFlag = -1; | 109 private int mRestoreSystemUiVisibilityFlag = -1; |
| 107 private Integer mRestoreOrientation = null; | 110 private Integer mRestoreOrientation = null; |
| 108 private long mNativeVrShellDelegate; | 111 private long mNativeVrShellDelegate; |
| 109 private boolean mRequestedWebVR; | 112 private boolean mRequestedWebVR; |
| 110 private long mLastVRExit; | 113 private long mLastVRExit; |
| 111 private boolean mListeningForWebVrActivate; | 114 private boolean mListeningForWebVrActivate; |
| 112 private boolean mListeningForWebVrActivateBeforePause; | 115 private boolean mListeningForWebVrActivateBeforePause; |
| 113 | 116 |
| 114 public VrShellDelegate(ChromeTabbedActivity activity) { | 117 /** |
| 115 mActivity = activity; | 118 * Called when the native library is first available. |
| 116 mVrClassesWrapper = createVrClassesWrapper(); | 119 */ |
| 120 public static void onNativeLibraryAvailable() { | |
| 121 nativeOnLibraryAvailable(); | |
| 117 } | 122 } |
| 118 | 123 |
| 119 /** | 124 /** |
| 120 * Updates mVrSupportLevel to the correct value. isVrCoreCompatible might re turn different value | 125 * @return A helper class for creating VR-specific classes that may not be a vailable at compile |
| 121 * at runtime. | 126 * time. |
| 122 */ | 127 */ |
| 123 // TODO(bshe): Find a place to call this function again, i.e. page refresh o r onResume. | 128 @VisibleForTesting |
| 124 // TODO(mthiesse): Clean this function up, lots of duplicated code. | 129 public static VrClassesWrapper getVrClassesWrapper() { |
| 125 private void updateVrSupportLevel() { | 130 if (sInstance != null) return sInstance.mVrClassesWrapper; |
| 126 if (mVrClassesWrapper == null || !isVrCoreCompatible()) { | 131 return createVrClassesWrapper(); |
| 127 mVrSupportLevel = VR_NOT_AVAILABLE; | |
| 128 mEnterVRIntent = null; | |
| 129 return; | |
| 130 } | |
| 131 | |
| 132 if (mVrDaydreamApi == null) { | |
| 133 mVrDaydreamApi = mVrClassesWrapper.createVrDaydreamApi(); | |
| 134 } | |
| 135 | |
| 136 // Check cardboard support for non-daydream devices. | |
| 137 if (!mVrDaydreamApi.isDaydreamReadyDevice()) { | |
| 138 // Supported Build version is determined by the webvr cardboard supp ort feature. | |
| 139 // Default is KITKAT unless specified via server side finch config. | |
| 140 if (Build.VERSION.SDK_INT < ChromeFeatureList.getFieldTrialParamByFe atureAsInt( | |
| 141 ChromeFeatureList.WEBVR_CARDBOAR D_SUPPORT, | |
| 142 MIN_SDK_VERSION_PARAM_NAME, | |
| 143 Build.VERSION_CODES.KITKAT)) { | |
| 144 mVrSupportLevel = VR_NOT_AVAILABLE; | |
| 145 mEnterVRIntent = null; | |
| 146 return; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 if (mEnterVRIntent == null) { | |
| 151 mEnterVRIntent = | |
| 152 mVrDaydreamApi.createVrIntent(new ComponentName(mActivity, V R_ACTIVITY_ALIAS)); | |
| 153 } | |
| 154 mVrSupportLevel = mVrDaydreamApi.isDaydreamReadyDevice() ? VR_DAYDREAM : VR_CARDBOARD; | |
| 155 } | 132 } |
| 156 | 133 |
| 157 /** | 134 /** |
| 158 * Should be called once the native library is loaded so that the native por tion of this class | 135 * Pauses VR Shell, if it needs to be paused. |
| 159 * can be initialized. | |
| 160 */ | 136 */ |
| 161 public void onNativeLibraryReady() { | 137 public static void maybePauseVR(ChromeActivity activity) { |
| 162 updateVrSupportLevel(); | 138 maybeUnregisterDaydreamIntent(activity); |
| 163 if (mVrSupportLevel == VR_NOT_AVAILABLE) return; | 139 if (sInstance == null) return; |
| 164 mNativeVrShellDelegate = nativeInit(); | 140 if (sInstance.mActivity != activity) { |
| 165 Choreographer choreographer = Choreographer.getInstance(); | 141 assert !sInstance.mInVr; |
| 166 choreographer.postFrameCallback(new FrameCallback() { | 142 return; |
| 167 @Override | 143 } |
| 168 public void doFrame(long frameTimeNanos) { | 144 sInstance.pauseVR(); |
| 169 Display display = ((WindowManager) mActivity.getSystemService( | 145 } |
| 170 Context.WINDOW_SERVICE)).getDefaultDisplay(); | 146 |
| 171 nativeUpdateVSyncInterval(mNativeVrShellDelegate, frameTimeNanos , | 147 /** |
| 172 1.0d / display.getRefreshRate()); | 148 * Resumes VR Shell, if it needs to be resumed. |
| 173 } | 149 */ |
| 174 }); | 150 public static void maybeResumeVR(ChromeActivity activity) { |
| 151 maybeRegisterDaydreamIntent(activity); | |
| 152 if (sInstance == null) return; | |
| 153 if (sInstance.mActivity != activity) { | |
| 154 assert !sInstance.mInVr; | |
| 155 return; | |
| 156 } | |
| 157 sInstance.resumeVR(); | |
| 158 } | |
| 159 | |
| 160 /** | |
| 161 * Whether or not we are currently in VR. | |
| 162 */ | |
| 163 public static boolean isInVR() { | |
| 164 if (sInstance == null) return false; | |
| 165 return sInstance.mInVr; | |
| 166 } | |
| 167 | |
| 168 /** | |
| 169 * See {@link ChromeActivity#handleBackPressed} | |
| 170 * Only handles the back press while in VR. | |
| 171 */ | |
| 172 public static boolean onBackPressed() { | |
| 173 if (sInstance == null) return false; | |
| 174 return sInstance.onBackPressedInternal(); | |
| 175 } | |
| 176 | |
| 177 /** | |
| 178 * Enters VR on the current tab if possible. | |
| 179 */ | |
| 180 public static void enterVRIfNecessary() { | |
| 181 boolean created_delegate = sInstance == null; | |
| 182 VrShellDelegate instance = getInstance(); | |
| 183 if (instance == null) return; | |
| 184 if (instance.enterVRInternal() == ENTER_VR_CANCELLED && created_delegate ) { | |
| 185 instance.destroy(); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 /** | |
| 190 * Handles a VR intent, entering VR in the process. | |
| 191 */ | |
| 192 public static void enterVRFromIntent(Intent intent) { | |
| 193 assert isDaydreamVrIntent(intent); | |
| 194 boolean created_delegate = sInstance == null; | |
| 195 VrShellDelegate instance = getInstance(); | |
| 196 if (instance == null) return; | |
| 197 if (!instance.enterVRFromIntent() && created_delegate) instance.destroy( ); | |
| 198 } | |
| 199 | |
| 200 /** | |
| 201 * Whether or not the intent is a Daydream VR Intent. | |
| 202 */ | |
| 203 public static boolean isDaydreamVrIntent(Intent intent) { | |
| 204 if (intent == null || intent.getCategories() == null) return false; | |
| 205 return intent.getCategories().contains(DAYDREAM_CATEGORY); | |
| 206 } | |
| 207 | |
| 208 /** | |
| 209 * Handles the result of the exit VR flow (DOFF). | |
| 210 */ | |
| 211 public static void onExitVRResult(int resultCode) { | |
| 212 if (sInstance == null) return; | |
| 213 sInstance.onExitVRResult(resultCode == Activity.RESULT_OK); | |
| 214 } | |
| 215 | |
| 216 public static int getVrSupportLevel(VrDaydreamApi daydreamApi, | |
| 217 VrCoreVersionChecker versionChecker, Tab tabToShowInfobarIn) { | |
| 218 if (!isVrCoreCompatible(versionChecker, tabToShowInfobarIn) || daydreamA pi == null | |
| 219 || versionChecker == null) { | |
| 220 return VR_NOT_AVAILABLE; | |
| 221 } | |
| 222 | |
| 223 if (daydreamApi.isDaydreamReadyDevice()) return VR_DAYDREAM; | |
| 224 | |
| 225 // Check cardboard support for non-daydream devices. Supported Build ver sion is determined | |
| 226 // by the webvr cardboard support feature. Default is KITKAT unless spec ified via server | |
| 227 // side finch config. | |
| 228 if (Build.VERSION.SDK_INT < ChromeFeatureList.getFieldTrialParamByFeatur eAsInt( | |
| 229 ChromeFeatureList.WEBVR_CARDBOARD_SU PPORT, | |
| 230 MIN_SDK_VERSION_PARAM_NAME, | |
| 231 Build.VERSION_CODES.KITKAT)) { | |
| 232 return VR_NOT_AVAILABLE; | |
| 233 } | |
| 234 | |
| 235 return VR_CARDBOARD; | |
| 236 } | |
| 237 | |
| 238 @CalledByNative | |
| 239 private static VrShellDelegate getInstance() { | |
| 240 if (sInstance != null) return sInstance; | |
| 241 if (!LibraryLoader.isInitialized()) return null; | |
| 242 Activity activity = ApplicationStatus.getLastTrackedFocusedActivity(); | |
| 243 // Note that we only support ChromeTabbedActivity for now. | |
| 244 if (activity == null || !(activity instanceof ChromeTabbedActivity)) ret urn null; | |
| 245 sInstance = new VrShellDelegate((ChromeActivity) activity); | |
| 246 | |
| 247 return sInstance; | |
| 175 } | 248 } |
| 176 | 249 |
| 177 @SuppressWarnings("unchecked") | 250 @SuppressWarnings("unchecked") |
| 178 private VrClassesWrapper createVrClassesWrapper() { | 251 private static VrClassesWrapper createVrClassesWrapper() { |
| 179 try { | 252 try { |
| 180 Class<? extends VrClassesWrapper> vrClassesBuilderClass = | 253 Class<? extends VrClassesWrapper> vrClassesBuilderClass = |
| 181 (Class<? extends VrClassesWrapper>) Class.forName( | 254 (Class<? extends VrClassesWrapper>) Class.forName( |
| 182 "org.chromium.chrome.browser.vr_shell.VrClassesWrapp erImpl"); | 255 "org.chromium.chrome.browser.vr_shell.VrClassesWrapp erImpl"); |
| 183 Constructor<?> vrClassesBuilderConstructor = | 256 Constructor<?> vrClassesBuilderConstructor = vrClassesBuilderClass.g etConstructor(); |
| 184 vrClassesBuilderClass.getConstructor(ChromeActivity.class); | 257 return (VrClassesWrapper) vrClassesBuilderConstructor.newInstance(); |
| 185 return (VrClassesWrapper) vrClassesBuilderConstructor.newInstance(mA ctivity); | |
| 186 } catch (ClassNotFoundException | InstantiationException | IllegalAccess Exception | 258 } catch (ClassNotFoundException | InstantiationException | IllegalAccess Exception |
| 187 | IllegalArgumentException | InvocationTargetException | NoSuchM ethodException e) { | 259 | IllegalArgumentException | InvocationTargetException | NoSuchM ethodException e) { |
| 188 if (!(e instanceof ClassNotFoundException)) { | 260 if (!(e instanceof ClassNotFoundException)) { |
| 189 Log.e(TAG, "Unable to instantiate VrClassesWrapper", e); | 261 Log.e(TAG, "Unable to instantiate VrClassesWrapper", e); |
| 190 } | 262 } |
| 191 return null; | 263 return null; |
| 192 } | 264 } |
| 193 } | 265 } |
| 194 | 266 |
| 267 private static PendingIntent getEnterVRPendingIntent( | |
| 268 VrDaydreamApi dayreamApi, Activity activity) { | |
| 269 return PendingIntent.getActivity(activity, 0, | |
| 270 dayreamApi.createVrIntent(new ComponentName(activity, VR_ACTIVIT Y_ALIAS)), | |
| 271 PendingIntent.FLAG_ONE_SHOT); | |
| 272 } | |
| 273 | |
| 274 private static void maybeRegisterDaydreamIntent(Activity activity) { | |
| 275 if (sInstance != null) return; // Will be handled in onResume. | |
| 276 if (!(activity instanceof ChromeTabbedActivity)) return; | |
| 277 VrClassesWrapper wrapper = createVrClassesWrapper(); | |
| 278 if (wrapper == null) return; | |
| 279 VrDaydreamApi api = wrapper.createVrDaydreamApi(activity); | |
| 280 if (api == null) return; | |
| 281 int vrSupportLevel = getVrSupportLevel(api, wrapper.createVrCoreVersionC hecker(), null); | |
| 282 if (isVrShellEnabled(vrSupportLevel)) registerDaydreamIntent(api, activi ty); | |
| 283 } | |
| 284 | |
| 285 private static void maybeUnregisterDaydreamIntent(Activity activity) { | |
| 286 if (sInstance != null) return; // Will be handled in onPause. | |
| 287 if (!(activity instanceof ChromeTabbedActivity)) return; | |
| 288 VrClassesWrapper wrapper = createVrClassesWrapper(); | |
| 289 if (wrapper == null) return; | |
| 290 VrDaydreamApi api = wrapper.createVrDaydreamApi(activity); | |
| 291 if (api == null) return; | |
| 292 unregisterDaydreamIntent(api); | |
| 293 } | |
| 294 | |
| 295 /** | |
| 296 * Registers the Intent to fire after phone inserted into a headset. | |
| 297 */ | |
| 298 private static void registerDaydreamIntent(VrDaydreamApi dayreamApi, Activit y activity) { | |
| 299 dayreamApi.registerDaydreamIntent(getEnterVRPendingIntent(dayreamApi, ac tivity)); | |
| 300 } | |
| 301 | |
| 302 /** | |
| 303 * Unregisters the Intent which registered by this context if any. | |
| 304 */ | |
| 305 private static void unregisterDaydreamIntent(VrDaydreamApi dayreamApi) { | |
| 306 dayreamApi.unregisterDaydreamIntent(); | |
| 307 } | |
| 308 | |
| 309 /** | |
| 310 * @return Whether or not VR Shell is currently enabled. | |
| 311 */ | |
| 312 private static boolean isVrShellEnabled(int vrSupportLevel) { | |
| 313 // Only enable ChromeVR (VrShell) on Daydream devices as it currently ne eds a Daydream | |
| 314 // controller. | |
| 315 if (vrSupportLevel != VR_DAYDREAM) return false; | |
| 316 return ChromeFeatureList.isEnabled(ChromeFeatureList.VR_SHELL); | |
| 317 } | |
| 318 | |
| 319 private VrShellDelegate(ChromeActivity activity) { | |
| 320 mActivity = activity; | |
| 321 mVrClassesWrapper = createVrClassesWrapper(); | |
| 322 updateVrSupportLevel(); | |
| 323 if (mVrSupportLevel == VR_NOT_AVAILABLE) return; | |
|
amp
2017/03/02 18:11:54
If VR is not available, we still contruct a VrShel
mthiesse
2017/03/02 20:01:58
Oops, meant to remove the early return. The native
| |
| 324 mNativeVrShellDelegate = nativeInit(); | |
| 325 Choreographer choreographer = Choreographer.getInstance(); | |
| 326 choreographer.postFrameCallback(new FrameCallback() { | |
| 327 @Override | |
| 328 public void doFrame(long frameTimeNanos) { | |
| 329 Display display = | |
| 330 ((WindowManager) mActivity.getSystemService(Context.WIND OW_SERVICE)) | |
| 331 .getDefaultDisplay(); | |
| 332 nativeUpdateVSyncInterval( | |
| 333 mNativeVrShellDelegate, frameTimeNanos, 1.0d / display.g etRefreshRate()); | |
| 334 } | |
| 335 }); | |
| 336 } | |
| 337 | |
| 338 /** | |
| 339 * Updates mVrSupportLevel to the correct value. isVrCoreCompatible might re turn different value | |
| 340 * at runtime. | |
| 341 */ | |
| 342 // TODO(bshe): Find a place to call this function again, i.e. page refresh o r onResume. | |
| 343 private void updateVrSupportLevel() { | |
| 344 if (mVrClassesWrapper == null) { | |
| 345 mVrSupportLevel = VR_NOT_AVAILABLE; | |
| 346 return; | |
| 347 } | |
| 348 if (mVrCoreVersionChecker == null) { | |
| 349 mVrCoreVersionChecker = mVrClassesWrapper.createVrCoreVersionChecker (); | |
| 350 } | |
| 351 if (mVrDaydreamApi == null) { | |
| 352 mVrDaydreamApi = mVrClassesWrapper.createVrDaydreamApi(mActivity); | |
| 353 } | |
| 354 mVrSupportLevel = getVrSupportLevel( | |
| 355 mVrDaydreamApi, mVrCoreVersionChecker, mActivity.getActivityTab( )); | |
| 356 } | |
| 357 | |
| 195 /** | 358 /** |
| 196 * Handle a VR intent, entering VR in the process unless we're unable to. | 359 * Handle a VR intent, entering VR in the process unless we're unable to. |
| 197 */ | 360 */ |
| 198 public void enterVRFromIntent(Intent intent) { | 361 private boolean enterVRFromIntent() { |
| 199 // Vr Intent is only used on Daydream devices. | 362 // Vr Intent is only used on Daydream devices. |
| 200 if (mVrSupportLevel != VR_DAYDREAM) return; | 363 if (mVrSupportLevel != VR_DAYDREAM) return false; |
| 201 assert isDaydreamVrIntent(intent); | |
| 202 if (mListeningForWebVrActivateBeforePause && !mRequestedWebVR) { | 364 if (mListeningForWebVrActivateBeforePause && !mRequestedWebVR) { |
| 203 nativeDisplayActivate(mNativeVrShellDelegate); | 365 nativeDisplayActivate(mNativeVrShellDelegate); |
| 204 return; | 366 return false; |
| 205 } | 367 } |
| 206 // Normally, if the active page doesn't have a vrdisplayactivate listene r, and WebVR was not | 368 // Normally, if the active page doesn't have a vrdisplayactivate listene r, and WebVR was not |
| 207 // presenting and VrShell was not enabled, we shouldn't enter VR and Day dream Homescreen | 369 // presenting and VrShell was not enabled, we shouldn't enter VR and Day dream Homescreen |
| 208 // should show after DON flow. But due to a failure in unregisterDaydrea mIntent, we still | 370 // should show after DON flow. But due to a failure in unregisterDaydrea mIntent, we still |
| 209 // try to enterVR. Here we detect this case and force switch to Daydream Homescreen. | 371 // try to enterVR. Here we detect this case and force switch to Daydream Homescreen. |
| 210 if (!mListeningForWebVrActivateBeforePause && !mRequestedWebVR && !isVrS hellEnabled()) { | 372 if (!mListeningForWebVrActivateBeforePause && !mRequestedWebVR |
| 373 && !isVrShellEnabled(mVrSupportLevel)) { | |
| 211 mVrDaydreamApi.launchVrHomescreen(); | 374 mVrDaydreamApi.launchVrHomescreen(); |
| 212 return; | 375 return false; |
| 213 } | 376 } |
| 214 | 377 |
| 215 if (mInVr) { | 378 if (mInVr) { |
| 216 setEnterVRResult(true); | 379 setEnterVRResult(true); |
| 217 return; | 380 return false; |
| 218 } | 381 } |
| 219 if (!canEnterVR(mActivity.getActivityTab())) { | 382 if (!canEnterVR(mActivity.getActivityTab())) { |
| 220 setEnterVRResult(false); | 383 setEnterVRResult(false); |
| 221 return; | 384 return false; |
| 222 } | 385 } |
| 223 if (mPaused) { | 386 if (mPaused) { |
| 224 // We can't enter VR before the application resumes, or we encounter bizarre crashes | 387 // We can't enter VR before the application resumes, or we encounter bizarre crashes |
| 225 // related to gpu surfaces. Set this flag to enter VR on the next re sume. | 388 // related to gpu surfaces. Set this flag to enter VR on the next re sume. |
| 226 prepareToEnterVR(); | 389 prepareToEnterVR(); |
| 227 mEnteringVr = true; | 390 mEnteringVr = true; |
| 228 } else { | 391 } else { |
| 229 enterVR(); | 392 enterVR(); |
| 230 } | 393 } |
| 394 return true; | |
| 231 } | 395 } |
| 232 | 396 |
| 233 private void prepareToEnterVR() { | 397 private void prepareToEnterVR() { |
| 234 if (mRestoreOrientation == null) { | 398 if (mRestoreOrientation == null) { |
| 235 mRestoreOrientation = mActivity.getRequestedOrientation(); | 399 mRestoreOrientation = mActivity.getRequestedOrientation(); |
| 236 } | 400 } |
| 237 mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSC APE); | 401 mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSC APE); |
| 238 setupVrModeWindowFlags(); | 402 setupVrModeWindowFlags(); |
| 239 } | 403 } |
| 240 | 404 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 252 return; | 416 return; |
| 253 } | 417 } |
| 254 mEnteringVr = false; | 418 mEnteringVr = false; |
| 255 if (!createVrShell()) { | 419 if (!createVrShell()) { |
| 256 if (mRestoreOrientation != null) mActivity.setRequestedOrientation(m RestoreOrientation); | 420 if (mRestoreOrientation != null) mActivity.setRequestedOrientation(m RestoreOrientation); |
| 257 mRestoreOrientation = null; | 421 mRestoreOrientation = null; |
| 258 clearVrModeWindowFlags(); | 422 clearVrModeWindowFlags(); |
| 259 setEnterVRResult(false); | 423 setEnterVRResult(false); |
| 260 return; | 424 return; |
| 261 } | 425 } |
| 262 mVrClassesWrapper.setVrModeEnabled(true); | 426 mVrClassesWrapper.setVrModeEnabled(mActivity, true); |
| 263 mInVr = true; | 427 mInVr = true; |
| 264 | 428 |
| 265 addVrViews(); | 429 addVrViews(); |
| 266 mVrShell.initializeNative(mActivity.getActivityTab(), mRequestedWebVR); | 430 mVrShell.initializeNative(mActivity.getActivityTab(), mRequestedWebVR); |
| 267 // onResume needs to be called on GvrLayout after initialization to make sure DON flow work | 431 // onResume needs to be called on GvrLayout after initialization to make sure DON flow work |
| 268 // properly. | 432 // properly. |
| 269 mVrShell.resume(); | 433 mVrShell.resume(); |
| 270 | 434 |
| 271 setEnterVRResult(true); | 435 setEnterVRResult(true); |
| 272 } | 436 } |
| 273 | 437 |
| 274 private void setEnterVRResult(boolean success) { | 438 private void setEnterVRResult(boolean success) { |
| 275 if (mRequestedWebVR) nativeSetPresentResult(mNativeVrShellDelegate, succ ess); | 439 if (mRequestedWebVR) nativeSetPresentResult(mNativeVrShellDelegate, succ ess); |
| 276 if (!success && !mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent()) ) { | 440 if (!success && !mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent()) ) { |
| 277 mVrClassesWrapper.setVrModeEnabled(false); | 441 mVrClassesWrapper.setVrModeEnabled(mActivity, false); |
| 278 } | 442 } |
| 279 mRequestedWebVR = false; | 443 mRequestedWebVR = false; |
| 280 } | 444 } |
| 281 | 445 |
| 282 /* package */ boolean canEnterVR(Tab tab) { | 446 /* package */ boolean canEnterVR(Tab tab) { |
| 283 if (!LibraryLoader.isInitialized()) { | 447 if (!LibraryLoader.isInitialized()) { |
| 284 return false; | 448 return false; |
| 285 } | 449 } |
| 286 // If vr isn't in the build, or we haven't initialized yet, or vr shell is not enabled and | 450 if (mVrSupportLevel == VR_NOT_AVAILABLE || mNativeVrShellDelegate == 0) return false; |
| 287 // this is not a web vr request, then return immediately. | 451 // If vr shell is not enabled and this is not a web vr request, then ret urn false. |
| 288 if (mVrSupportLevel == VR_NOT_AVAILABLE || mNativeVrShellDelegate == 0 | 452 if (!isVrShellEnabled(mVrSupportLevel) |
| 289 || (!isVrShellEnabled() && !(mRequestedWebVR || mListeningForWeb VrActivate))) { | 453 && !(mRequestedWebVR || mListeningForWebVrActivate)) { |
| 290 return false; | 454 return false; |
| 291 } | 455 } |
| 292 // TODO(mthiesse): When we have VR UI for opening new tabs, etc., allow VR Shell to be | 456 // TODO(mthiesse): When we have VR UI for opening new tabs, etc., allow VR Shell to be |
| 293 // entered without any current tabs. | 457 // entered without any current tabs. |
| 294 if (tab == null) { | 458 if (tab == null) { |
| 295 return false; | 459 return false; |
| 296 } | 460 } |
| 297 // For now we don't handle sad tab page. crbug.com/661609 | 461 // For now we don't handle sad tab page. crbug.com/661609 |
| 298 if (tab.isShowingSadTab()) { | 462 if (tab.isShowingSadTab()) { |
| 299 return false; | 463 return false; |
| 300 } | 464 } |
| 301 // crbug.com/667781 | 465 // crbug.com/667781 |
| 302 if (MultiWindowUtils.getInstance().isInMultiWindowMode(mActivity)) { | 466 if (MultiWindowUtils.getInstance().isInMultiWindowMode(mActivity)) { |
| 303 return false; | 467 return false; |
| 304 } | 468 } |
| 305 return true; | 469 return true; |
| 306 } | 470 } |
| 307 | 471 |
| 308 @CalledByNative | 472 @CalledByNative |
| 309 private void presentRequested() { | 473 private void presentRequested() { |
| 310 // TODO(mthiesse): There's a GVR bug where they're not calling us back w ith the intent we | 474 // TODO(mthiesse): There's a GVR bug where they're not calling us back w ith the intent we |
| 311 // ask them to when we call DaydreamApi#launchInVr. As a temporary hack, remember locally | 475 // ask them to when we call DaydreamApi#launchInVr. As a temporary hack, remember locally |
| 312 // that we want to enter webVR. | 476 // that we want to enter webVR. |
| 313 mRequestedWebVR = true; | 477 mRequestedWebVR = true; |
| 314 switch (enterVRIfNecessary()) { | 478 switch (enterVRInternal()) { |
| 315 case ENTER_VR_NOT_NECESSARY: | 479 case ENTER_VR_NOT_NECESSARY: |
| 316 mVrShell.setWebVrModeEnabled(true); | 480 mVrShell.setWebVrModeEnabled(true); |
| 317 nativeSetPresentResult(mNativeVrShellDelegate, true); | 481 nativeSetPresentResult(mNativeVrShellDelegate, true); |
| 318 mRequestedWebVR = false; | 482 mRequestedWebVR = false; |
| 319 break; | 483 break; |
| 320 case ENTER_VR_CANCELLED: | 484 case ENTER_VR_CANCELLED: |
| 321 nativeSetPresentResult(mNativeVrShellDelegate, false); | 485 nativeSetPresentResult(mNativeVrShellDelegate, false); |
| 322 mRequestedWebVR = false; | 486 mRequestedWebVR = false; |
| 323 break; | 487 break; |
| 324 case ENTER_VR_REQUESTED: | 488 case ENTER_VR_REQUESTED: |
| 325 break; | 489 break; |
| 326 case ENTER_VR_SUCCEEDED: | 490 case ENTER_VR_SUCCEEDED: |
| 327 nativeSetPresentResult(mNativeVrShellDelegate, true); | 491 nativeSetPresentResult(mNativeVrShellDelegate, true); |
| 328 mRequestedWebVR = false; | 492 mRequestedWebVR = false; |
| 329 break; | 493 break; |
| 330 default: | 494 default: |
| 331 Log.e(TAG, "Unexpected enum."); | 495 Log.e(TAG, "Unexpected enum."); |
| 332 } | 496 } |
| 333 } | 497 } |
| 334 | 498 |
| 335 /** | 499 /** |
| 336 * Enters VR Shell if necessary, displaying browser UI and tab contents in V R. | 500 * Enters VR Shell if necessary, displaying browser UI and tab contents in V R. |
| 337 */ | 501 */ |
| 338 @EnterVRResult | 502 @EnterVRResult |
| 339 public int enterVRIfNecessary() { | 503 private int enterVRInternal() { |
| 340 // Update VR support level as it can change at runtime | 504 // Update VR support level as it can change at runtime |
| 341 updateVrSupportLevel(); | 505 updateVrSupportLevel(); |
| 342 if (mVrSupportLevel == VR_NOT_AVAILABLE) return ENTER_VR_CANCELLED; | 506 if (mVrSupportLevel == VR_NOT_AVAILABLE) return ENTER_VR_CANCELLED; |
| 343 if (mInVr) return ENTER_VR_NOT_NECESSARY; | 507 if (mInVr) return ENTER_VR_NOT_NECESSARY; |
| 344 if (!canEnterVR(mActivity.getActivityTab())) return ENTER_VR_CANCELLED; | 508 if (!canEnterVR(mActivity.getActivityTab())) return ENTER_VR_CANCELLED; |
| 345 | 509 |
| 346 if (mVrSupportLevel == VR_CARDBOARD || !mVrDaydreamApi.isDaydreamCurrent Viewer()) { | 510 if (mVrSupportLevel == VR_CARDBOARD || !mVrDaydreamApi.isDaydreamCurrent Viewer()) { |
| 347 // Avoid using launchInVr which would trigger DON flow regardless cu rrent viewer type | 511 // Avoid using launchInVr which would trigger DON flow regardless cu rrent viewer type |
| 348 // due to the lack of support for unexported activities. | 512 // due to the lack of support for unexported activities. |
| 349 enterVR(); | 513 enterVR(); |
| 350 } else { | 514 } else { |
| 351 if (!mVrDaydreamApi.launchInVr(getPendingEnterVRIntent())) return EN TER_VR_CANCELLED; | 515 if (!mVrDaydreamApi.launchInVr(getEnterVRPendingIntent(mVrDaydreamAp i, mActivity))) { |
| 516 return ENTER_VR_CANCELLED; | |
| 517 } | |
| 352 } | 518 } |
| 353 return ENTER_VR_REQUESTED; | 519 return ENTER_VR_REQUESTED; |
| 354 } | 520 } |
| 355 | 521 |
| 356 @CalledByNative | 522 @CalledByNative |
| 357 private boolean exitWebVR() { | 523 private boolean exitWebVR() { |
| 358 if (!mInVr) return false; | 524 if (!mInVr) return false; |
| 359 mVrShell.setWebVrModeEnabled(false); | 525 mVrShell.setWebVrModeEnabled(false); |
| 360 if (mVrSupportLevel == VR_CARDBOARD) { | 526 if (mVrSupportLevel == VR_CARDBOARD) { |
| 361 // Transition screen is not available for Cardboard only (non-Daydre am) devices. | 527 // Transition screen is not available for Cardboard only (non-Daydre am) devices. |
| 362 // TODO(bshe): Fix this once b/33490788 is fixed. | 528 // TODO(bshe): Fix this once b/33490788 is fixed. |
| 363 shutdownVR(false /* isPausing */, false /* showTransition */); | 529 shutdownVR(false /* isPausing */, false /* showTransition */); |
| 364 } else { | 530 } else { |
| 365 // TODO(bajones): Once VR Shell can be invoked outside of WebVR this | 531 // TODO(bajones): Once VR Shell can be invoked outside of WebVR this |
| 366 // should no longer exit the shell outright. Need a way to determine | 532 // should no longer exit the shell outright. Need a way to determine |
| 367 // how VrShell was created. | 533 // how VrShell was created. |
| 368 shutdownVR(false /* isPausing */, !isVrShellEnabled() /* showTransit ion */); | 534 shutdownVR( |
| 535 false /* isPausing */, !isVrShellEnabled(mVrSupportLevel) /* showTransition */); | |
| 369 } | 536 } |
| 370 return true; | 537 return true; |
| 371 } | 538 } |
| 372 | 539 |
| 373 /** | 540 private void resumeVR() { |
| 374 * Resumes VR Shell. | |
| 375 */ | |
| 376 public void maybeResumeVR() { | |
| 377 mPaused = false; | 541 mPaused = false; |
| 378 if (mVrSupportLevel == VR_NOT_AVAILABLE) return; | 542 if (mVrSupportLevel == VR_NOT_AVAILABLE) return; |
| 379 if (mVrSupportLevel == VR_DAYDREAM | 543 if (mVrSupportLevel == VR_DAYDREAM |
| 380 && (isVrShellEnabled() || mListeningForWebVrActivateBeforePause) ) { | 544 && (isVrShellEnabled(mVrSupportLevel) || mListeningForWebVrActiv ateBeforePause)) { |
| 381 registerDaydreamIntent(); | 545 registerDaydreamIntent(mVrDaydreamApi, mActivity); |
| 382 } | 546 } |
| 383 | 547 |
| 384 if (mEnteringVr) { | 548 if (mEnteringVr) { |
| 385 enterVR(); | 549 enterVR(); |
| 386 } else if (mRequestedWebVR) { | 550 } else if (mRequestedWebVR) { |
| 387 // If this is still set, it means the user backed out of the DON flo w, and we won't be | 551 // If this is still set, it means the user backed out of the DON flo w, and we won't be |
| 388 // receiving an intent from daydream. | 552 // receiving an intent from daydream. |
| 389 nativeSetPresentResult(mNativeVrShellDelegate, false); | 553 nativeSetPresentResult(mNativeVrShellDelegate, false); |
| 390 mRequestedWebVR = false; | 554 mRequestedWebVR = false; |
| 391 } | 555 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 402 oldPolicy = StrictMode.allowThreadDiskWrites(); | 566 oldPolicy = StrictMode.allowThreadDiskWrites(); |
| 403 try { | 567 try { |
| 404 mVrShell.resume(); | 568 mVrShell.resume(); |
| 405 } catch (IllegalArgumentException e) { | 569 } catch (IllegalArgumentException e) { |
| 406 Log.e(TAG, "Unable to resume VrShell", e); | 570 Log.e(TAG, "Unable to resume VrShell", e); |
| 407 } finally { | 571 } finally { |
| 408 StrictMode.setThreadPolicy(oldPolicy); | 572 StrictMode.setThreadPolicy(oldPolicy); |
| 409 } | 573 } |
| 410 } else if (mVrSupportLevel == VR_DAYDREAM && mVrDaydreamApi.isDaydreamCu rrentViewer() | 574 } else if (mVrSupportLevel == VR_DAYDREAM && mVrDaydreamApi.isDaydreamCu rrentViewer() |
| 411 && mLastVRExit + REENTER_VR_TIMEOUT_MS > SystemClock.uptimeMilli s()) { | 575 && mLastVRExit + REENTER_VR_TIMEOUT_MS > SystemClock.uptimeMilli s()) { |
| 412 enterVRIfNecessary(); | 576 enterVRInternal(); |
| 413 } | 577 } |
| 414 } | 578 } |
| 415 | 579 |
| 416 /** | 580 private void pauseVR() { |
| 417 * Pauses VR Shell. | |
| 418 */ | |
| 419 public void maybePauseVR() { | |
| 420 mPaused = true; | 581 mPaused = true; |
| 421 if (mVrSupportLevel == VR_NOT_AVAILABLE) return; | 582 if (mVrSupportLevel == VR_NOT_AVAILABLE) return; |
| 422 | 583 |
| 423 if (mVrSupportLevel == VR_DAYDREAM) { | 584 if (mVrSupportLevel == VR_DAYDREAM) { |
| 424 unregisterDaydreamIntent(); | 585 unregisterDaydreamIntent(mVrDaydreamApi); |
| 425 | 586 |
| 426 // When the active web page has a vrdisplayactivate event handler, | 587 // When the active web page has a vrdisplayactivate event handler, |
| 427 // mListeningForWebVrActivate should be set to true, which means a v rdisplayactive event | 588 // mListeningForWebVrActivate should be set to true, which means a v rdisplayactive event |
| 428 // should be fired once DON flow finished. However, DON flow will pa use our activity, | 589 // should be fired once DON flow finished. However, DON flow will pa use our activity, |
| 429 // which makes the active page becomes invisible. And the event fire s before the active | 590 // which makes the active page becomes invisible. And the event fire s before the active |
| 430 // page becomes visible again after DON finished. So here we remembe r the value of | 591 // page becomes visible again after DON finished. So here we remembe r the value of |
| 431 // mListeningForWebVrActivity before pause and use this value to dec ide if | 592 // mListeningForWebVrActivity before pause and use this value to dec ide if |
| 432 // vrdisplayactivate event should be dispatched in enterVRFromIntent . | 593 // vrdisplayactivate event should be dispatched in enterVRFromIntent . |
| 433 mListeningForWebVrActivateBeforePause = mListeningForWebVrActivate; | 594 mListeningForWebVrActivateBeforePause = mListeningForWebVrActivate; |
| 434 } | 595 } |
| 435 nativeOnPause(mNativeVrShellDelegate); | 596 nativeOnPause(mNativeVrShellDelegate); |
| 436 | 597 |
| 437 // TODO(mthiesse): When VR Shell lives in its own activity, and integrat es with Daydream | 598 // TODO(mthiesse): When VR Shell lives in its own activity, and integrat es with Daydream |
| 438 // home, pause instead of exiting VR here. For now, because VR Apps shou ldn't show up in the | 599 // home, pause instead of exiting VR here. For now, because VR Apps shou ldn't show up in the |
| 439 // non-VR recents, and we don't want ChromeTabbedActivity disappearing, exit VR. | 600 // non-VR recents, and we don't want ChromeTabbedActivity disappearing, exit VR. |
| 440 shutdownVR(true /* isPausing */, false /* showTransition */); | 601 shutdownVR(true /* isPausing */, false /* showTransition */); |
| 441 } | 602 } |
| 442 | 603 |
| 443 /** | 604 private boolean onBackPressedInternal() { |
| 444 * See {@link ChromeActivity#handleBackPressed} | |
| 445 */ | |
| 446 public boolean onBackPressed() { | |
| 447 if (mVrSupportLevel == VR_NOT_AVAILABLE) return false; | 605 if (mVrSupportLevel == VR_NOT_AVAILABLE) return false; |
| 448 if (!mInVr) return false; | 606 if (!mInVr) return false; |
| 449 shutdownVR(false /* isPausing */, false /* showTransition */); | 607 shutdownVR(false /* isPausing */, false /* showTransition */); |
| 450 return true; | 608 return true; |
| 451 } | 609 } |
| 452 | 610 |
| 453 public void onExitVRResult(int resultCode) { | 611 private void onExitVRResult(boolean success) { |
| 454 assert mVrSupportLevel != VR_NOT_AVAILABLE; | 612 assert mVrSupportLevel != VR_NOT_AVAILABLE; |
| 455 if (resultCode == Activity.RESULT_OK) { | 613 // For now, we don't handle re-entering VR when exit fails, so keep tryi ng to exit. |
| 456 mVrClassesWrapper.setVrModeEnabled(false); | 614 if (!success && sInstance.mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent())) return; |
| 457 } else { | 615 sInstance.mVrClassesWrapper.setVrModeEnabled(sInstance.mActivity, false) ; |
| 458 // For now, we don't handle re-entering VR when exit fails, so keep trying to exit. | |
| 459 if (!mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent())) { | |
| 460 mVrClassesWrapper.setVrModeEnabled(false); | |
| 461 } | |
| 462 } | |
| 463 } | |
| 464 | |
| 465 private PendingIntent getPendingEnterVRIntent() { | |
| 466 return PendingIntent.getActivity(mActivity, 0, mEnterVRIntent, PendingIn tent.FLAG_ONE_SHOT); | |
| 467 } | |
| 468 | |
| 469 /** | |
| 470 * Registers the Intent to fire after phone inserted into a headset. | |
| 471 */ | |
| 472 private void registerDaydreamIntent() { | |
| 473 mVrDaydreamApi.registerDaydreamIntent(getPendingEnterVRIntent()); | |
| 474 } | |
| 475 | |
| 476 /** | |
| 477 * Unregisters the Intent which registered by this context if any. | |
| 478 */ | |
| 479 private void unregisterDaydreamIntent() { | |
| 480 mVrDaydreamApi.unregisterDaydreamIntent(); | |
| 481 } | 616 } |
| 482 | 617 |
| 483 @CalledByNative | 618 @CalledByNative |
| 484 private long createNonPresentingNativeContext() { | 619 private long createNonPresentingNativeContext() { |
| 485 if (mVrClassesWrapper == null) return 0; | 620 if (mVrClassesWrapper == null) return 0; |
| 486 mNonPresentingGvrContext = mVrClassesWrapper.createNonPresentingGvrConte xt(); | 621 mNonPresentingGvrContext = mVrClassesWrapper.createNonPresentingGvrConte xt(mActivity); |
| 487 if (mNonPresentingGvrContext == null) return 0; | 622 if (mNonPresentingGvrContext == null) return 0; |
| 488 return mNonPresentingGvrContext.getNativeGvrContext(); | 623 return mNonPresentingGvrContext.getNativeGvrContext(); |
| 489 } | 624 } |
| 490 | 625 |
| 491 @CalledByNative | 626 @CalledByNative |
| 492 private void shutdownNonPresentingNativeContext() { | 627 private void shutdownNonPresentingNativeContext() { |
| 493 mNonPresentingGvrContext.shutdown(); | 628 mNonPresentingGvrContext.shutdown(); |
| 494 mNonPresentingGvrContext = null; | 629 mNonPresentingGvrContext = null; |
| 495 } | 630 } |
| 496 | 631 |
| 497 @CalledByNative | 632 @CalledByNative |
| 498 private void setListeningForWebVrActivate(boolean listening) { | 633 private void setListeningForWebVrActivate(boolean listening) { |
| 499 // Non-Daydream devices may not have the concept of display activate. So disable | 634 // Non-Daydream devices may not have the concept of display activate. So disable |
| 500 // mListeningForWebVrActivate for them. | 635 // mListeningForWebVrActivate for them. |
| 501 if (mVrSupportLevel != VR_DAYDREAM) return; | 636 if (mVrSupportLevel != VR_DAYDREAM) return; |
| 502 mListeningForWebVrActivate = listening; | 637 mListeningForWebVrActivate = listening; |
| 503 if (listening) { | 638 if (listening) { |
| 504 registerDaydreamIntent(); | 639 registerDaydreamIntent(mVrDaydreamApi, mActivity); |
| 505 } else { | 640 } else { |
| 506 unregisterDaydreamIntent(); | 641 unregisterDaydreamIntent(mVrDaydreamApi); |
| 507 } | 642 } |
| 508 } | 643 } |
| 509 | 644 |
| 510 /** | 645 /** |
| 511 * Exits VR Shell, performing all necessary cleanup. | 646 * Exits VR Shell, performing all necessary cleanup. |
| 512 */ | 647 */ |
| 513 /* package */ void shutdownVR(boolean isPausing, boolean showTransition) { | 648 /* package */ void shutdownVR(boolean isPausing, boolean showTransition) { |
| 514 if (!mInVr) return; | 649 if (!mInVr) return; |
| 515 mInVr = false; | 650 mInVr = false; |
| 516 mRequestedWebVR = false; | 651 mRequestedWebVR = false; |
| 517 boolean transition = mVrSupportLevel == VR_DAYDREAM && showTransition; | 652 boolean transition = mVrSupportLevel == VR_DAYDREAM && showTransition; |
| 518 if (!isPausing) { | 653 if (!isPausing) { |
| 519 if (!transition || !mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new In tent())) { | 654 if (!transition || !mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new In tent())) { |
| 520 mVrClassesWrapper.setVrModeEnabled(false); | 655 mVrClassesWrapper.setVrModeEnabled(mActivity, false); |
| 521 } | 656 } |
| 522 } else { | 657 } else { |
| 523 mVrClassesWrapper.setVrModeEnabled(false); | 658 mVrClassesWrapper.setVrModeEnabled(mActivity, false); |
| 524 mLastVRExit = SystemClock.uptimeMillis(); | 659 mLastVRExit = SystemClock.uptimeMillis(); |
| 525 } | 660 } |
| 526 if (mRestoreOrientation != null) mActivity.setRequestedOrientation(mRest oreOrientation); | 661 if (mRestoreOrientation != null) mActivity.setRequestedOrientation(mRest oreOrientation); |
| 527 mRestoreOrientation = null; | 662 mRestoreOrientation = null; |
| 528 mVrShell.pause(); | 663 mVrShell.pause(); |
| 529 removeVrViews(); | 664 removeVrViews(); |
| 530 clearVrModeWindowFlags(); | 665 clearVrModeWindowFlags(); |
| 531 destroyVrShell(); | 666 destroyVrShell(); |
| 532 mActivity.getFullscreenManager().setPositionsForTabToNonFullscreen(); | 667 mActivity.getFullscreenManager().setPositionsForTabToNonFullscreen(); |
| 533 } | 668 } |
| 534 | 669 |
| 535 private boolean isVrCoreCompatible() { | 670 private static boolean isVrCoreCompatible( |
| 536 assert mVrClassesWrapper != null; | 671 VrCoreVersionChecker versionChecker, Tab tabToShowInfobarIn) { |
| 537 if (mVrCoreVersionChecker == null) { | |
| 538 mVrCoreVersionChecker = mVrClassesWrapper.createVrCoreVersionChecker (); | |
| 539 } | |
| 540 | |
| 541 return verifyOrUpdateVrServices( | 672 return verifyOrUpdateVrServices( |
| 542 mVrCoreVersionChecker.getVrCoreCompatibility(), mActivity.getAct ivityTab()); | 673 versionChecker.getVrCoreCompatibility(), tabToShowInfobarIn); |
| 543 } | 674 } |
| 544 | 675 |
| 545 private boolean verifyOrUpdateVrServices(int vrCoreCompatibility, Tab tab) { | 676 private static boolean verifyOrUpdateVrServices(int vrCoreCompatibility, Tab tab) { |
| 546 if (vrCoreCompatibility == VrCoreVersionChecker.VR_READY) { | 677 if (vrCoreCompatibility == VrCoreVersionChecker.VR_READY) { |
| 547 return true; | 678 return true; |
| 548 } | 679 } |
| 549 if (tab == null) { | 680 if (tab == null) { |
| 550 return false; | 681 return false; |
| 551 } | 682 } |
| 552 // Make sure OS is supported before showing the user a prompt. | 683 // Make sure OS is supported before showing the user a prompt. |
| 553 if (Build.VERSION.SDK_INT < ChromeFeatureList.getFieldTrialParamByFeatur eAsInt( | 684 if (Build.VERSION.SDK_INT < ChromeFeatureList.getFieldTrialParamByFeatur eAsInt( |
| 554 ChromeFeatureList.WEBVR_CARDBOARD_SU PPORT, | 685 ChromeFeatureList.WEBVR_CARDBOARD_SU PPORT, |
| 555 MIN_SDK_VERSION_PARAM_NAME, | 686 MIN_SDK_VERSION_PARAM_NAME, |
| 556 Build.VERSION_CODES.KITKAT)) { | 687 Build.VERSION_CODES.KITKAT)) { |
| 557 return false; | 688 return false; |
| 558 } | 689 } |
| 559 | 690 final Activity activity = tab.getActivity(); |
| 560 String infobarText; | 691 String infobarText; |
| 561 String buttonText; | 692 String buttonText; |
| 562 if (vrCoreCompatibility == VrCoreVersionChecker.VR_NOT_AVAILABLE) { | 693 if (vrCoreCompatibility == VrCoreVersionChecker.VR_NOT_AVAILABLE) { |
| 563 // Supported, but not installed. Ask user to install instead of upgr ade. | 694 // Supported, but not installed. Ask user to install instead of upgr ade. |
| 564 infobarText = mActivity.getString(R.string.vr_services_check_infobar _install_text); | 695 infobarText = activity.getString(R.string.vr_services_check_infobar_ install_text); |
| 565 buttonText = mActivity.getString(R.string.vr_services_check_infobar_ install_button); | 696 buttonText = activity.getString(R.string.vr_services_check_infobar_i nstall_button); |
| 566 } else if (vrCoreCompatibility == VrCoreVersionChecker.VR_OUT_OF_DATE) { | 697 } else if (vrCoreCompatibility == VrCoreVersionChecker.VR_OUT_OF_DATE) { |
| 567 infobarText = mActivity.getString(R.string.vr_services_check_infobar _update_text); | 698 infobarText = activity.getString(R.string.vr_services_check_infobar_ update_text); |
| 568 buttonText = mActivity.getString(R.string.vr_services_check_infobar_ update_button); | 699 buttonText = activity.getString(R.string.vr_services_check_infobar_u pdate_button); |
| 569 } else { | 700 } else { |
| 570 Log.e(TAG, "Unknown VrCore compatibility: " + vrCoreCompatibility); | 701 Log.e(TAG, "Unknown VrCore compatibility: " + vrCoreCompatibility); |
| 571 return false; | 702 return false; |
| 572 } | 703 } |
| 573 | 704 |
| 574 SimpleConfirmInfoBarBuilder.create(tab, | 705 SimpleConfirmInfoBarBuilder.create(tab, |
| 575 new SimpleConfirmInfoBarBuilder.Listener() { | 706 new SimpleConfirmInfoBarBuilder.Listener() { |
| 576 @Override | 707 @Override |
| 577 public void onInfoBarDismissed() {} | 708 public void onInfoBarDismissed() {} |
| 578 | 709 |
| 579 @Override | 710 @Override |
| 580 public boolean onInfoBarButtonClicked(boolean isPrimary) { | 711 public boolean onInfoBarButtonClicked(boolean isPrimary) { |
| 581 mActivity.startActivity(new Intent(Intent.ACTION_VIEW, | 712 activity.startActivity(new Intent(Intent.ACTION_VIEW, |
| 582 Uri.parse("market://details?id=" + VR_CORE_PACKA GE_ID))); | 713 Uri.parse("market://details?id=" + VR_CORE_PACKA GE_ID))); |
| 583 return false; | 714 return false; |
| 584 } | 715 } |
| 585 }, | 716 }, |
| 586 InfoBarIdentifier.VR_SERVICES_UPGRADE_ANDROID, R.drawable.vr_ser vices, infobarText, | 717 InfoBarIdentifier.VR_SERVICES_UPGRADE_ANDROID, R.drawable.vr_ser vices, infobarText, |
| 587 buttonText, null, true); | 718 buttonText, null, true); |
| 588 return false; | 719 return false; |
| 589 } | 720 } |
| 590 | 721 |
| 591 private boolean createVrShell() { | 722 private boolean createVrShell() { |
| 592 if (mVrClassesWrapper == null) return false; | 723 if (mVrClassesWrapper == null) return false; |
| 593 mVrShell = mVrClassesWrapper.createVrShell(this, mActivity.getCompositor ViewHolder()); | 724 mTabModelSelector = mActivity.getCompositorViewHolder().detachForVR(); |
| 725 if (mTabModelSelector == null) return false; | |
| 726 mVrShell = mVrClassesWrapper.createVrShell(mActivity, this, mTabModelSel ector); | |
| 594 return mVrShell != null; | 727 return mVrShell != null; |
| 595 } | 728 } |
| 596 | 729 |
| 597 private void addVrViews() { | 730 private void addVrViews() { |
| 598 FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView(); | 731 FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView(); |
| 599 LayoutParams params = new FrameLayout.LayoutParams( | 732 LayoutParams params = new FrameLayout.LayoutParams( |
| 600 ViewGroup.LayoutParams.MATCH_PARENT, | 733 ViewGroup.LayoutParams.MATCH_PARENT, |
| 601 ViewGroup.LayoutParams.MATCH_PARENT); | 734 ViewGroup.LayoutParams.MATCH_PARENT); |
| 602 decor.addView(mVrShell.getContainer(), params); | 735 decor.addView(mVrShell.getContainer(), params); |
| 603 mActivity.setUIVisibilityForVR(View.GONE); | 736 mActivity.onEnterVR(); |
| 604 } | 737 } |
| 605 | 738 |
| 606 private void removeVrViews() { | 739 private void removeVrViews() { |
| 607 mActivity.setUIVisibilityForVR(View.VISIBLE); | 740 mActivity.onExitVR(); |
| 608 FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView(); | 741 FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView(); |
| 609 decor.removeView(mVrShell.getContainer()); | 742 decor.removeView(mVrShell.getContainer()); |
| 610 } | 743 } |
| 611 | 744 |
| 612 private void setupVrModeWindowFlags() { | 745 private void setupVrModeWindowFlags() { |
| 613 if (mRestoreSystemUiVisibilityFlag == -1) { | 746 if (mRestoreSystemUiVisibilityFlag == -1) { |
| 614 mRestoreSystemUiVisibilityFlag = mActivity.getWindow().getDecorView( ) | 747 mRestoreSystemUiVisibilityFlag = mActivity.getWindow().getDecorView( ) |
| 615 .getSystemUiVisibility(); | 748 .getSystemUiVisibility(); |
| 616 } | 749 } |
| 617 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCRE EN_ON); | 750 mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCRE EN_ON); |
| 618 mActivity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_U I_FLAG_LAYOUT_STABLE | 751 mActivity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_U I_FLAG_LAYOUT_STABLE |
| 619 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | 752 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
| 620 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HI DE_NAVIGATION | 753 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HI DE_NAVIGATION |
| 621 | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE _STICKY); | 754 | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE _STICKY); |
| 622 } | 755 } |
| 623 | 756 |
| 624 private void clearVrModeWindowFlags() { | 757 private void clearVrModeWindowFlags() { |
| 625 mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SC REEN_ON); | 758 mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SC REEN_ON); |
| 626 if (mRestoreSystemUiVisibilityFlag != -1) { | 759 if (mRestoreSystemUiVisibilityFlag != -1) { |
| 627 mActivity.getWindow().getDecorView() | 760 mActivity.getWindow().getDecorView() |
| 628 .setSystemUiVisibility(mRestoreSystemUiVisibilityFlag); | 761 .setSystemUiVisibility(mRestoreSystemUiVisibilityFlag); |
| 629 } | 762 } |
| 630 mRestoreSystemUiVisibilityFlag = -1; | 763 mRestoreSystemUiVisibilityFlag = -1; |
| 631 } | 764 } |
| 632 | 765 |
| 633 /** | 766 /** |
| 634 * Clean up VrShell, and associated native objects. | 767 * Clean up VrShell, and associated native objects. |
| 635 */ | 768 */ |
| 636 public void destroyVrShell() { | 769 private void destroyVrShell() { |
| 637 if (mVrShell != null) { | 770 if (mVrShell != null) { |
| 638 mVrShell.teardown(); | 771 mVrShell.teardown(); |
| 639 mVrShell = null; | 772 mVrShell = null; |
| 773 mActivity.getCompositorViewHolder().onExitVR(mTabModelSelector); | |
| 640 } | 774 } |
| 641 } | 775 } |
| 642 | 776 |
| 643 /** | 777 /** |
| 644 * Whether or not the intent is a Daydream VR Intent. | |
| 645 */ | |
| 646 public boolean isDaydreamVrIntent(Intent intent) { | |
| 647 if (intent == null || intent.getCategories() == null) return false; | |
| 648 return intent.getCategories().contains(DAYDREAM_CATEGORY); | |
| 649 } | |
| 650 | |
| 651 /** | |
| 652 * Whether or not we are currently in VR. | |
| 653 */ | |
| 654 public boolean isInVR() { | |
| 655 return mInVr; | |
| 656 } | |
| 657 | |
| 658 /** | |
| 659 * @return Whether or not VR Shell is currently enabled. | |
| 660 */ | |
| 661 private boolean isVrShellEnabled() { | |
| 662 // Only enable ChromeVR (VrShell) on Daydream devices as it currently ne eds a Daydream | |
| 663 // controller. | |
| 664 if (mVrSupportLevel != VR_DAYDREAM) return false; | |
| 665 return ChromeFeatureList.isEnabled(ChromeFeatureList.VR_SHELL); | |
| 666 } | |
| 667 | |
| 668 /** | |
| 669 * @param api The VrDaydreamApi object this delegate will use instead of the default one | 778 * @param api The VrDaydreamApi object this delegate will use instead of the default one |
| 670 */ | 779 */ |
| 671 @VisibleForTesting | 780 @VisibleForTesting |
| 672 public void overrideDaydreamApiForTesting(VrDaydreamApi api) { | 781 public void overrideDaydreamApiForTesting(VrDaydreamApi api) { |
| 673 mVrDaydreamApi = api; | 782 mVrDaydreamApi = api; |
| 674 } | 783 } |
| 675 | 784 |
| 676 /** | 785 /** |
| 677 * @return Pointer to the native VrShellDelegate object. | 786 * @return Pointer to the native VrShellDelegate object. |
| 678 */ | 787 */ |
| 679 @CalledByNative | 788 @CalledByNative |
| 680 private long getNativePointer() { | 789 private long getNativePointer() { |
| 681 return mNativeVrShellDelegate; | 790 return mNativeVrShellDelegate; |
| 682 } | 791 } |
| 683 | 792 |
| 684 @CalledByNative | 793 @CalledByNative |
| 685 private void showTab(int id) { | 794 private void showTab(int id) { |
| 686 Tab tab = mActivity.getTabModelSelector().getTabById(id); | 795 Tab tab = mActivity.getTabModelSelector().getTabById(id); |
| 687 if (tab == null) { | 796 if (tab == null) { |
| 688 return; | 797 return; |
| 689 } | 798 } |
| 690 int index = mActivity.getTabModelSelector().getModel(tab.isIncognito()). indexOf(tab); | 799 int index = mActivity.getTabModelSelector().getModel(tab.isIncognito()). indexOf(tab); |
| 691 if (index == TabModel.INVALID_TAB_INDEX) { | 800 if (index == TabModel.INVALID_TAB_INDEX) { |
| 692 return; | 801 return; |
| 693 } | 802 } |
| 694 TabModelUtils.setIndex(mActivity.getTabModelSelector().getModel(tab.isIn cognito()), index); | 803 TabModelUtils.setIndex(mActivity.getTabModelSelector().getModel(tab.isIn cognito()), index); |
| 695 } | 804 } |
| 696 | 805 |
| 806 private void destroy() { | |
| 807 if (sInstance == null) return; | |
| 808 if (mNativeVrShellDelegate != 0) nativeDestroy(mNativeVrShellDelegate); | |
| 809 sInstance = null; | |
| 810 } | |
| 811 | |
| 697 private native long nativeInit(); | 812 private native long nativeInit(); |
| 813 private static native void nativeOnLibraryAvailable(); | |
| 698 private native void nativeSetPresentResult(long nativeVrShellDelegate, boole an result); | 814 private native void nativeSetPresentResult(long nativeVrShellDelegate, boole an result); |
| 699 private native void nativeDisplayActivate(long nativeVrShellDelegate); | 815 private native void nativeDisplayActivate(long nativeVrShellDelegate); |
| 700 private native void nativeUpdateVSyncInterval(long nativeVrShellDelegate, lo ng timebaseNanos, | 816 private native void nativeUpdateVSyncInterval(long nativeVrShellDelegate, lo ng timebaseNanos, |
| 701 double intervalSeconds); | 817 double intervalSeconds); |
| 702 private native void nativeOnPause(long nativeVrShellDelegate); | 818 private native void nativeOnPause(long nativeVrShellDelegate); |
| 703 private native void nativeOnResume(long nativeVrShellDelegate); | 819 private native void nativeOnResume(long nativeVrShellDelegate); |
| 820 private native void nativeDestroy(long nativeVrShellDelegate); | |
| 704 } | 821 } |
| OLD | NEW |