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 |