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.Intent; | 10 import android.content.Intent; |
11 import android.content.pm.ActivityInfo; | 11 import android.content.pm.ActivityInfo; |
12 import android.os.StrictMode; | 12 import android.os.StrictMode; |
13 import android.os.SystemClock; | 13 import android.os.SystemClock; |
| 14 import android.support.annotation.IntDef; |
14 import android.view.View; | 15 import android.view.View; |
15 import android.view.ViewGroup; | 16 import android.view.ViewGroup; |
16 import android.view.ViewGroup.LayoutParams; | 17 import android.view.ViewGroup.LayoutParams; |
17 import android.view.WindowManager; | 18 import android.view.WindowManager; |
18 import android.widget.FrameLayout; | 19 import android.widget.FrameLayout; |
19 | 20 |
20 import org.chromium.base.Log; | 21 import org.chromium.base.Log; |
21 import org.chromium.base.annotations.CalledByNative; | 22 import org.chromium.base.annotations.CalledByNative; |
22 import org.chromium.base.annotations.JNINamespace; | 23 import org.chromium.base.annotations.JNINamespace; |
23 import org.chromium.base.library_loader.LibraryLoader; | 24 import org.chromium.base.library_loader.LibraryLoader; |
24 import org.chromium.chrome.browser.ChromeFeatureList; | 25 import org.chromium.chrome.browser.ChromeFeatureList; |
25 import org.chromium.chrome.browser.ChromeTabbedActivity; | 26 import org.chromium.chrome.browser.ChromeTabbedActivity; |
26 import org.chromium.chrome.browser.tab.EmptyTabObserver; | 27 import org.chromium.chrome.browser.tab.EmptyTabObserver; |
27 import org.chromium.chrome.browser.tab.Tab; | 28 import org.chromium.chrome.browser.tab.Tab; |
28 import org.chromium.chrome.browser.tab.TabObserver; | 29 import org.chromium.chrome.browser.tab.TabObserver; |
29 import org.chromium.content_public.common.BrowserControlsState; | 30 import org.chromium.content_public.common.BrowserControlsState; |
30 | 31 |
| 32 import java.lang.annotation.Retention; |
| 33 import java.lang.annotation.RetentionPolicy; |
31 import java.lang.reflect.Constructor; | 34 import java.lang.reflect.Constructor; |
32 import java.lang.reflect.InvocationTargetException; | 35 import java.lang.reflect.InvocationTargetException; |
33 | 36 |
34 /** | 37 /** |
35 * Manages interactions with the VR Shell. | 38 * Manages interactions with the VR Shell. |
36 */ | 39 */ |
37 @JNINamespace("vr_shell") | 40 @JNINamespace("vr_shell") |
38 public class VrShellDelegate { | 41 public class VrShellDelegate { |
39 private static final String TAG = "VrShellDelegate"; | 42 private static final String TAG = "VrShellDelegate"; |
40 // Pseudo-random number to avoid request id collisions. | 43 // Pseudo-random number to avoid request id collisions. |
41 public static final int EXIT_VR_RESULT = 721251; | 44 public static final int EXIT_VR_RESULT = 721251; |
42 | 45 |
| 46 public static final int ENTER_VR_NOT_NECESSARY = 0; |
| 47 public static final int ENTER_VR_CANCELLED = 1; |
| 48 public static final int ENTER_VR_REQUESTED = 2; |
| 49 @Retention(RetentionPolicy.SOURCE) |
| 50 @IntDef({ENTER_VR_NOT_NECESSARY, ENTER_VR_CANCELLED, ENTER_VR_REQUESTED}) |
| 51 public @interface EnterVRResult {} |
| 52 |
43 // TODO(bshe): These should be replaced by string provided by NDK. Currently
, it only available | 53 // TODO(bshe): These should be replaced by string provided by NDK. Currently
, it only available |
44 // in SDK and we don't want add dependency to SDK just to get these strings. | 54 // in SDK and we don't want add dependency to SDK just to get these strings. |
45 private static final String DAYDREAM_VR_EXTRA = "android.intent.extra.VR_LAU
NCH"; | 55 private static final String DAYDREAM_VR_EXTRA = "android.intent.extra.VR_LAU
NCH"; |
46 private static final String DAYDREAM_CATEGORY = "com.google.intent.category.
DAYDREAM"; | 56 private static final String DAYDREAM_CATEGORY = "com.google.intent.category.
DAYDREAM"; |
47 private static final String CARDBOARD_CATEGORY = "com.google.intent.category
.CARDBOARD"; | 57 private static final String CARDBOARD_CATEGORY = "com.google.intent.category
.CARDBOARD"; |
48 | 58 |
49 private static final String VR_ACTIVITY_ALIAS = | 59 private static final String VR_ACTIVITY_ALIAS = |
50 "org.chromium.chrome.browser.VRChromeTabbedActivity"; | 60 "org.chromium.chrome.browser.VRChromeTabbedActivity"; |
51 private static final String DAYDREAM_DON_TYPE = "DAYDREAM_DON_TYPE"; | |
52 | |
53 private static final int DAYDREAM_DON_TYPE_VR_SHELL = 0; | |
54 private static final int DAYDREAM_DON_TYPE_WEBVR = 1; | |
55 private static final int DAYDREAM_DON_TYPE_AUTO = 2; | |
56 | 61 |
57 private static final long REENTER_VR_TIMEOUT_MS = 1000; | 62 private static final long REENTER_VR_TIMEOUT_MS = 1000; |
58 | 63 |
59 private final ChromeTabbedActivity mActivity; | 64 private final ChromeTabbedActivity mActivity; |
60 private final TabObserver mTabObserver; | 65 private final TabObserver mTabObserver; |
| 66 private final Intent mEnterVRIntent; |
61 | 67 |
62 private boolean mVrAvailable; | 68 private boolean mVrAvailable; |
63 private Boolean mVrShellEnabled; | 69 private Boolean mVrShellEnabled; |
64 | 70 |
65 private Class<? extends VrShell> mVrShellClass; | 71 private Class<? extends VrShell> mVrShellClass; |
66 private Class<? extends NonPresentingGvrContext> mNonPresentingGvrContextCla
ss; | 72 private Class<? extends NonPresentingGvrContext> mNonPresentingGvrContextCla
ss; |
67 private Class<? extends VrDaydreamApi> mVrDaydreamApiClass; | 73 private Class<? extends VrDaydreamApi> mVrDaydreamApiClass; |
68 private Class<? extends VrCoreVersionChecker> mVrCoreVersionCheckerClass; | 74 private Class<? extends VrCoreVersionChecker> mVrCoreVersionCheckerClass; |
69 private VrShell mVrShell; | 75 private VrShell mVrShell; |
70 private NonPresentingGvrContext mNonPresentingGvrContext; | 76 private NonPresentingGvrContext mNonPresentingGvrContext; |
71 private VrDaydreamApi mVrDaydreamApi; | 77 private VrDaydreamApi mVrDaydreamApi; |
72 private VrCoreVersionChecker mVrCoreVersionChecker; | 78 private VrCoreVersionChecker mVrCoreVersionChecker; |
73 private boolean mInVr; | 79 private boolean mInVr; |
74 private int mRestoreSystemUiVisibilityFlag = -1; | 80 private int mRestoreSystemUiVisibilityFlag = -1; |
75 private int mRestoreOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIE
D; | 81 private int mRestoreOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIE
D; |
76 private long mNativeVrShellDelegate; | 82 private long mNativeVrShellDelegate; |
77 private Tab mTab; | 83 private Tab mTab; |
78 private boolean mRequestedWebVR; | 84 private boolean mRequestedWebVR; |
79 private long mLastVRExit; | 85 private long mLastVRExit; |
80 | 86 |
81 public VrShellDelegate(ChromeTabbedActivity activity) { | 87 public VrShellDelegate(ChromeTabbedActivity activity) { |
82 mActivity = activity; | 88 mActivity = activity; |
83 mVrAvailable = maybeFindVrClasses() && isVrCoreCompatible(); | 89 mVrAvailable = maybeFindVrClasses() && isVrCoreCompatible() && createVrD
aydreamApi(); |
84 createVrDaydreamApi(); | 90 if (mVrAvailable) { |
| 91 mEnterVRIntent = mVrDaydreamApi.createVrIntent( |
| 92 new ComponentName(mActivity, VR_ACTIVITY_ALIAS)); |
| 93 } else { |
| 94 mEnterVRIntent = null; |
| 95 } |
85 mTabObserver = new EmptyTabObserver() { | 96 mTabObserver = new EmptyTabObserver() { |
86 @Override | 97 @Override |
87 public void onContentChanged(Tab tab) { | 98 public void onContentChanged(Tab tab) { |
88 if (tab.getNativePage() != null || tab.isShowingSadTab()) { | 99 if (tab.getNativePage() != null || tab.isShowingSadTab()) { |
89 // For now we don't handle native pages. crbug.com/661609 | 100 // For now we don't handle native pages. crbug.com/661609 |
90 exitVRIfNecessary(true); | 101 exitVRIfNecessary(true); |
91 } | 102 } |
92 } | 103 } |
93 | 104 |
94 @Override | 105 @Override |
95 public void onWebContentsSwapped(Tab tab, boolean didStartLoad, bool
ean didFinishLoad) { | 106 public void onWebContentsSwapped(Tab tab, boolean didStartLoad, bool
ean didFinishLoad) { |
96 // TODO(mthiesse): Update the native WebContents pointer and com
positor. This | 107 // TODO(mthiesse): Update the native WebContents pointer and com
positor. This |
97 // doesn't seem to get triggered in VR Shell currently, but that
's likely to change | 108 // doesn't seem to get triggered in VR Shell currently, but that
's likely to change |
98 // when we have omnibar navigation. | 109 // when we have omnibar navigation. |
99 } | 110 } |
100 }; | 111 }; |
101 } | 112 } |
102 | 113 |
103 /** | 114 /** |
104 * Should be called once the native library is loaded so that the native por
tion of this | 115 * Should be called once the native library is loaded so that the native por
tion of this |
105 * class can be initialized. | 116 * class can be initialized. |
106 */ | 117 */ |
107 public void onNativeLibraryReady() { | 118 public void onNativeLibraryReady() { |
108 if (mVrAvailable) { | 119 if (!mVrAvailable) return; |
109 mNativeVrShellDelegate = nativeInit(); | 120 mNativeVrShellDelegate = nativeInit(); |
110 } | |
111 } | 121 } |
112 | 122 |
113 @SuppressWarnings("unchecked") | 123 @SuppressWarnings("unchecked") |
114 private boolean maybeFindVrClasses() { | 124 private boolean maybeFindVrClasses() { |
115 try { | 125 try { |
116 mVrShellClass = (Class<? extends VrShell>) Class.forName( | 126 mVrShellClass = (Class<? extends VrShell>) Class.forName( |
117 "org.chromium.chrome.browser.vr_shell.VrShellImpl"); | 127 "org.chromium.chrome.browser.vr_shell.VrShellImpl"); |
118 mNonPresentingGvrContextClass = | 128 mNonPresentingGvrContextClass = |
119 (Class<? extends NonPresentingGvrContext>) Class.forName( | 129 (Class<? extends NonPresentingGvrContext>) Class.forName( |
120 "org.chromium.chrome.browser.vr_shell.NonPresentingG
vrContextImpl"); | 130 "org.chromium.chrome.browser.vr_shell.NonPresentingG
vrContextImpl"); |
121 mVrDaydreamApiClass = (Class<? extends VrDaydreamApi>) Class.forName
( | 131 mVrDaydreamApiClass = (Class<? extends VrDaydreamApi>) Class.forName
( |
122 "org.chromium.chrome.browser.vr_shell.VrDaydreamApiImpl"); | 132 "org.chromium.chrome.browser.vr_shell.VrDaydreamApiImpl"); |
123 mVrCoreVersionCheckerClass = (Class<? extends VrCoreVersionChecker>)
Class.forName( | 133 mVrCoreVersionCheckerClass = (Class<? extends VrCoreVersionChecker>)
Class.forName( |
124 "org.chromium.chrome.browser.vr_shell.VrCoreVersionCheckerIm
pl"); | 134 "org.chromium.chrome.browser.vr_shell.VrCoreVersionCheckerIm
pl"); |
125 return true; | 135 return true; |
126 } catch (ClassNotFoundException e) { | 136 } catch (ClassNotFoundException e) { |
127 mVrShellClass = null; | 137 mVrShellClass = null; |
128 mNonPresentingGvrContextClass = null; | 138 mNonPresentingGvrContextClass = null; |
129 mVrDaydreamApiClass = null; | 139 mVrDaydreamApiClass = null; |
130 mVrCoreVersionCheckerClass = null; | 140 mVrCoreVersionCheckerClass = null; |
131 return false; | 141 return false; |
132 } | 142 } |
133 } | 143 } |
134 | 144 |
135 /** | 145 /** |
136 * Handle a VR intent, entering VR in the process. | 146 * Handle a VR intent, entering VR in the process. |
137 */ | 147 */ |
138 public boolean enterVRFromIntent(Intent intent) { | 148 public void enterVRFromIntent(Intent intent) { |
| 149 if (!mVrAvailable) return; |
139 assert isVrIntent(intent); | 150 assert isVrIntent(intent); |
140 int transitionType = intent.getIntExtra(DAYDREAM_DON_TYPE, DAYDREAM_DON_
TYPE_VR_SHELL); | 151 if (enterVR()) { |
141 if (!isVrShellEnabled()) { | 152 if (mRequestedWebVR) { |
142 assert transitionType != DAYDREAM_DON_TYPE_VR_SHELL; | 153 nativeSetPresentResult(mNativeVrShellDelegate, true); |
| 154 mVrShell.setWebVrModeEnabled(true); |
| 155 } |
| 156 } else { |
| 157 if (mRequestedWebVR) nativeSetPresentResult(mNativeVrShellDelegate,
false); |
| 158 mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent()); |
143 } | 159 } |
144 | 160 |
145 boolean inWebVR = transitionType == DAYDREAM_DON_TYPE_WEBVR | |
146 || (transitionType == DAYDREAM_DON_TYPE_AUTO | |
147 && (!isVrShellEnabled() || mRequestedWebVR)); | |
148 mRequestedWebVR = false; | 161 mRequestedWebVR = false; |
149 Tab tab = mActivity.getActivityTab(); | 162 } |
150 if (!canEnterVR(inWebVR, tab)) return false; | |
151 | 163 |
152 // TODO(mthiesse): We should handle switching between webVR and VR Shell
mode through | 164 private boolean enterVR() { |
153 // intents. | |
154 if (mInVr) return true; | 165 if (mInVr) return true; |
155 | |
156 mVrDaydreamApi.setVrModeEnabled(true); | 166 mVrDaydreamApi.setVrModeEnabled(true); |
157 | 167 |
158 mTab = tab; | 168 Tab tab = mActivity.getActivityTab(); |
159 mTab.addObserver(mTabObserver); | 169 if (!canEnterVR(tab)) return false; |
160 | 170 |
161 mRestoreOrientation = mActivity.getRequestedOrientation(); | 171 mRestoreOrientation = mActivity.getRequestedOrientation(); |
162 mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSC
APE); | 172 mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSC
APE); |
163 if (!createVrShell()) { | 173 if (!createVrShell()) { |
164 mActivity.setRequestedOrientation(mRestoreOrientation); | 174 mActivity.setRequestedOrientation(mRestoreOrientation); |
165 return false; | 175 return false; |
166 } | 176 } |
| 177 mInVr = true; |
| 178 mTab = tab; |
| 179 mTab.addObserver(mTabObserver); |
167 addVrViews(); | 180 addVrViews(); |
168 setupVrModeWindowFlags(); | 181 setupVrModeWindowFlags(); |
169 mVrShell.initializeNative(mTab, this); | 182 mVrShell.initializeNative(mTab, this); |
170 if (inWebVR) mVrShell.setWebVrModeEnabled(true); | |
171 mVrShell.setCloseButtonListener(new Runnable() { | 183 mVrShell.setCloseButtonListener(new Runnable() { |
172 @Override | 184 @Override |
173 public void run() { | 185 public void run() { |
174 exitVRIfNecessary(true); | 186 exitVRIfNecessary(true); |
175 } | 187 } |
176 }); | 188 }); |
177 // onResume needs to be called on GvrLayout after initialization to make
sure DON flow work | 189 // onResume needs to be called on GvrLayout after initialization to make
sure DON flow work |
178 // properly. | 190 // properly. |
179 mVrShell.resume(); | 191 mVrShell.resume(); |
180 mInVr = true; | |
181 mTab.updateFullscreenEnabledState(); | 192 mTab.updateFullscreenEnabledState(); |
182 return true; | 193 return true; |
183 } | 194 } |
184 | 195 |
185 private boolean canEnterVR(boolean inWebVR, Tab tab) { | 196 private boolean canEnterVR(Tab tab) { |
186 if (!LibraryLoader.isInitialized()) { | 197 if (!LibraryLoader.isInitialized()) { |
187 return false; | 198 return false; |
188 } | 199 } |
189 // If vr isn't in the build, or we haven't initialized yet, or vr shell
is not enabled and | 200 // If vr isn't in the build, or we haven't initialized yet, or vr shell
is not enabled and |
190 // this is not a web vr request, then return immediately. | 201 // this is not a web vr request, then return immediately. |
191 if (!mVrAvailable || mNativeVrShellDelegate == 0 || (!isVrShellEnabled()
&& !inWebVR)) { | 202 if (!mVrAvailable || mNativeVrShellDelegate == 0 |
| 203 || (!isVrShellEnabled() && !mRequestedWebVR)) { |
192 return false; | 204 return false; |
193 } | 205 } |
194 // TODO(mthiesse): When we have VR UI for opening new tabs, etc., allow
VR Shell to be | 206 // TODO(mthiesse): When we have VR UI for opening new tabs, etc., allow
VR Shell to be |
195 // entered without any current tabs. | 207 // entered without any current tabs. |
196 if (tab == null || tab.getContentViewCore() == null) { | 208 if (tab == null || tab.getContentViewCore() == null) { |
197 return false; | 209 return false; |
198 } | 210 } |
199 | 211 |
200 // For now we don't handle native pages. crbug.com/661609 | 212 // For now we don't handle native pages. crbug.com/661609 |
201 if (tab.getNativePage() != null || tab.isShowingSadTab()) { | 213 if (tab.getNativePage() != null || tab.isShowingSadTab()) { |
202 return false; | 214 return false; |
203 } | 215 } |
204 return true; | 216 return true; |
205 } | 217 } |
206 | 218 |
| 219 @CalledByNative |
| 220 private void presentRequested(boolean inWebVR) { |
| 221 // TODO(mthiesse): There's a GVR bug where they're not calling us back w
ith the |
| 222 // intent we ask them to when we call DaydreamApi#launchInVr. As a tempo
rary hack, |
| 223 // remember locally that we want to enter webVR. |
| 224 mRequestedWebVR = inWebVR; |
| 225 switch (enterVRIfNecessary()) { |
| 226 case ENTER_VR_NOT_NECESSARY: |
| 227 mVrShell.setWebVrModeEnabled(true); |
| 228 nativeSetPresentResult(mNativeVrShellDelegate, true); |
| 229 mRequestedWebVR = false; |
| 230 break; |
| 231 case ENTER_VR_CANCELLED: |
| 232 nativeSetPresentResult(mNativeVrShellDelegate, false); |
| 233 mRequestedWebVR = false; |
| 234 break; |
| 235 case ENTER_VR_REQUESTED: |
| 236 break; |
| 237 } |
| 238 } |
| 239 |
207 /** | 240 /** |
208 * Enters VR Shell, displaying browser UI and tab contents in VR. | 241 * Enters VR Shell if necessary, displaying browser UI and tab contents in V
R. |
209 * | |
210 * @param inWebVR If true should begin displaying WebVR content rather than
the VrShell UI. | |
211 */ | 242 */ |
212 @CalledByNative | 243 @EnterVRResult |
213 public void enterVRIfNecessary(boolean inWebVR) { | 244 public int enterVRIfNecessary() { |
214 if (mInVr) { | 245 if (!mVrAvailable) return ENTER_VR_CANCELLED; |
215 if (inWebVR) mVrShell.setWebVrModeEnabled(true); | 246 if (mInVr) return ENTER_VR_NOT_NECESSARY; |
216 return; | 247 if (!canEnterVR(mActivity.getActivityTab())) return ENTER_VR_CANCELLED; |
217 } | |
218 if (!canEnterVR(inWebVR, mActivity.getActivityTab())) return; | |
219 | 248 |
220 // TODO(mthiesse): There's a GVR bug where they're not calling us back w
ith the intent we | 249 mVrDaydreamApi.launchInVr(getPendingEnterVRIntent()); |
221 // ask them to when we call DaydreamApi#launchInVr. As a temporary hack,
remember locally | 250 return ENTER_VR_REQUESTED; |
222 // that we want to enter webVR. | |
223 mRequestedWebVR = inWebVR; | |
224 Intent intent = createDaydreamIntent( | |
225 inWebVR ? DAYDREAM_DON_TYPE_WEBVR : DAYDREAM_DON_TYPE_VR_SHELL); | |
226 | |
227 mVrDaydreamApi.launchInVr( | |
228 PendingIntent.getActivity(mActivity, 0, intent, PendingIntent.FL
AG_ONE_SHOT)); | |
229 } | 251 } |
230 | 252 |
231 @CalledByNative | 253 @CalledByNative |
232 private boolean exitWebVR() { | 254 private boolean exitWebVR() { |
233 if (!mInVr) return false; | 255 if (!mInVr) return false; |
234 mVrShell.setWebVrModeEnabled(false); | 256 mVrShell.setWebVrModeEnabled(false); |
235 // TODO(bajones): Once VR Shell can be invoked outside of WebVR this | 257 // TODO(bajones): Once VR Shell can be invoked outside of WebVR this |
236 // should no longer exit the shell outright. Need a way to determine | 258 // should no longer exit the shell outright. Need a way to determine |
237 // how VrShell was created. | 259 // how VrShell was created. |
238 shutdownVR(true); | 260 shutdownVR(true); |
239 return true; | 261 return true; |
240 } | 262 } |
241 | 263 |
242 /** | 264 /** |
243 * Resumes VR Shell. | 265 * Resumes VR Shell. |
244 */ | 266 */ |
245 public void maybeResumeVR() { | 267 public void maybeResumeVR() { |
| 268 if (!mVrAvailable) return; |
| 269 // TODO(mthiesse): Register the intent when on a page that supports WebV
R, even if VrShell |
| 270 // isn't enabled. |
246 if (isVrShellEnabled()) { | 271 if (isVrShellEnabled()) { |
247 registerDaydreamIntent(); | 272 registerDaydreamIntent(); |
248 } | 273 } |
| 274 // If this is still set, it means the user backed out of the DON flow, a
nd we won't be |
| 275 // receiving an intent from daydream. |
| 276 if (mRequestedWebVR) { |
| 277 nativeSetPresentResult(mNativeVrShellDelegate, false); |
| 278 mRequestedWebVR = false; |
| 279 } |
249 | 280 |
250 // TODO(bshe): Ideally, we do not need two gvr context exist at the same
time. We can | 281 // TODO(bshe): Ideally, we do not need two gvr context exist at the same
time. We can |
251 // probably shutdown non presenting gvr when presenting and create a new
one after exit | 282 // probably shutdown non presenting gvr when presenting and create a new
one after exit |
252 // presenting. See crbug.com/655242 | 283 // presenting. See crbug.com/655242 |
253 if (mNonPresentingGvrContext != null) { | 284 if (mNonPresentingGvrContext != null) { |
254 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites
(); | 285 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites
(); |
255 try { | 286 try { |
256 mNonPresentingGvrContext.resume(); | 287 mNonPresentingGvrContext.resume(); |
257 } catch (IllegalArgumentException e) { | 288 } catch (IllegalArgumentException e) { |
258 Log.e(TAG, "Unable to resume mNonPresentingGvrContext", e); | 289 Log.e(TAG, "Unable to resume mNonPresentingGvrContext", e); |
259 } finally { | 290 } finally { |
260 StrictMode.setThreadPolicy(oldPolicy); | 291 StrictMode.setThreadPolicy(oldPolicy); |
261 } | 292 } |
262 } | 293 } |
263 | 294 |
264 if (mInVr) { | 295 if (mInVr) { |
265 setupVrModeWindowFlags(); | 296 setupVrModeWindowFlags(); |
266 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites
(); | 297 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites
(); |
267 try { | 298 try { |
268 mVrShell.resume(); | 299 mVrShell.resume(); |
269 } catch (IllegalArgumentException e) { | 300 } catch (IllegalArgumentException e) { |
270 Log.e(TAG, "Unable to resume VrShell", e); | 301 Log.e(TAG, "Unable to resume VrShell", e); |
271 } finally { | 302 } finally { |
272 StrictMode.setThreadPolicy(oldPolicy); | 303 StrictMode.setThreadPolicy(oldPolicy); |
273 } | 304 } |
274 } else if (mLastVRExit + REENTER_VR_TIMEOUT_MS > SystemClock.uptimeMilli
s()) { | 305 } else if (mLastVRExit + REENTER_VR_TIMEOUT_MS > SystemClock.uptimeMilli
s()) { |
275 enterVRIfNecessary(mRequestedWebVR); | 306 enterVRIfNecessary(); |
276 } | 307 } |
277 } | 308 } |
278 | 309 |
279 /** | 310 /** |
280 * Pauses VR Shell. | 311 * Pauses VR Shell. |
281 */ | 312 */ |
282 public void maybePauseVR() { | 313 public void maybePauseVR() { |
283 if (isVrShellEnabled()) { | 314 if (!mVrAvailable) return; |
284 unregisterDaydreamIntent(); | 315 unregisterDaydreamIntent(); |
285 } | |
286 | 316 |
287 if (mNonPresentingGvrContext != null) { | 317 if (mNonPresentingGvrContext != null) { |
288 mNonPresentingGvrContext.pause(); | 318 mNonPresentingGvrContext.pause(); |
289 } | 319 } |
290 | 320 |
291 // TODO(mthiesse): When VR Shell lives in its own activity, and integrat
es with Daydream | 321 // TODO(mthiesse): When VR Shell lives in its own activity, and integrat
es with Daydream |
292 // home, pause instead of exiting VR here. For now, because VR Apps shou
ldn't show up in the | 322 // home, pause instead of exiting VR here. For now, because VR Apps shou
ldn't show up in the |
293 // non-VR recents, and we don't want ChromeTabbedActivity disappearing,
exit VR. | 323 // non-VR recents, and we don't want ChromeTabbedActivity disappearing,
exit VR. |
294 exitVRIfNecessary(false); | 324 exitVRIfNecessary(false); |
295 } | 325 } |
296 | 326 |
297 /** | 327 /** |
298 * Exits the current VR mode (WebVR or VRShell) | 328 * Exits the current VR mode (WebVR or VRShell) |
299 * @return Whether or not we exited VR. | 329 * @return Whether or not we exited VR. |
300 */ | 330 */ |
301 public boolean exitVRIfNecessary(boolean returnTo2D) { | 331 public boolean exitVRIfNecessary(boolean returnTo2D) { |
| 332 if (!mVrAvailable) return false; |
302 if (!mInVr) return false; | 333 if (!mInVr) return false; |
303 shutdownVR(returnTo2D); | 334 shutdownVR(returnTo2D); |
304 return true; | 335 return true; |
305 } | 336 } |
306 | 337 |
307 public void onExitVRResult(int resultCode) { | 338 public void onExitVRResult(int resultCode) { |
| 339 assert mVrAvailable; |
308 if (resultCode == Activity.RESULT_OK) { | 340 if (resultCode == Activity.RESULT_OK) { |
309 mVrDaydreamApi.setVrModeEnabled(false); | 341 mVrDaydreamApi.setVrModeEnabled(false); |
310 } else { | 342 } else { |
311 // For now, we don't handle re-entering VR when exit fails, so keep
trying to exit. | 343 // For now, we don't handle re-entering VR when exit fails, so keep
trying to exit. |
312 mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent()); | 344 mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent()); |
313 } | 345 } |
314 } | 346 } |
315 | 347 |
316 private Intent createDaydreamIntent(int transitionType) { | 348 private PendingIntent getPendingEnterVRIntent() { |
317 if (mVrDaydreamApi == null) return null; | 349 return PendingIntent.getActivity(mActivity, 0, mEnterVRIntent, PendingIn
tent.FLAG_ONE_SHOT); |
318 // TODO(bshe): Ideally, this should go through ChromeLauncherActivity. T
o avoid polluting | |
319 // metrics, use the VR Activity alias for now. | |
320 Intent intent = mVrDaydreamApi.createVrIntent( | |
321 new ComponentName(mActivity, VR_ACTIVITY_ALIAS)); | |
322 intent.putExtra(DAYDREAM_DON_TYPE, transitionType); | |
323 return intent; | |
324 } | 350 } |
325 | 351 |
326 /** | 352 /** |
327 * Registers the Intent to fire after phone inserted into a headset. | 353 * Registers the Intent to fire after phone inserted into a headset. |
328 */ | 354 */ |
329 private void registerDaydreamIntent() { | 355 private void registerDaydreamIntent() { |
330 if (mVrDaydreamApi == null) return; | 356 mVrDaydreamApi.registerDaydreamIntent(getPendingEnterVRIntent()); |
331 Intent intent = createDaydreamIntent(DAYDREAM_DON_TYPE_AUTO); | |
332 mVrDaydreamApi.registerDaydreamIntent( | |
333 PendingIntent.getActivity(mActivity, 0, intent, PendingIntent.FL
AG_ONE_SHOT)); | |
334 } | 357 } |
335 | 358 |
336 /** | 359 /** |
337 * Unregisters the Intent which registered by this context if any. | 360 * Unregisters the Intent which registered by this context if any. |
338 */ | 361 */ |
339 private void unregisterDaydreamIntent() { | 362 private void unregisterDaydreamIntent() { |
340 if (mVrDaydreamApi != null) { | 363 mVrDaydreamApi.unregisterDaydreamIntent(); |
341 mVrDaydreamApi.unregisterDaydreamIntent(); | |
342 } | |
343 } | 364 } |
344 | 365 |
345 @CalledByNative | 366 @CalledByNative |
346 private long createNonPresentingNativeContext() { | 367 private long createNonPresentingNativeContext() { |
347 if (!mVrAvailable) return 0; | 368 if (!mVrAvailable) return 0; |
348 | 369 |
349 try { | 370 try { |
350 Constructor<?> nonPresentingGvrContextConstructor = | 371 Constructor<?> nonPresentingGvrContextConstructor = |
351 mNonPresentingGvrContextClass.getConstructor(Activity.class)
; | 372 mNonPresentingGvrContextClass.getConstructor(Activity.class)
; |
352 mNonPresentingGvrContext = | 373 mNonPresentingGvrContext = |
(...skipping 11 matching lines...) Expand all Loading... |
364 private void shutdownNonPresentingNativeContext() { | 385 private void shutdownNonPresentingNativeContext() { |
365 mNonPresentingGvrContext.shutdown(); | 386 mNonPresentingGvrContext.shutdown(); |
366 mNonPresentingGvrContext = null; | 387 mNonPresentingGvrContext = null; |
367 } | 388 } |
368 | 389 |
369 /** | 390 /** |
370 * Exits VR Shell, performing all necessary cleanup. | 391 * Exits VR Shell, performing all necessary cleanup. |
371 */ | 392 */ |
372 private void shutdownVR(boolean returnTo2D) { | 393 private void shutdownVR(boolean returnTo2D) { |
373 if (!mInVr) return; | 394 if (!mInVr) return; |
| 395 mRequestedWebVR = false; |
374 if (returnTo2D) { | 396 if (returnTo2D) { |
375 mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent()); | 397 mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent()); |
376 } else { | 398 } else { |
377 mVrDaydreamApi.setVrModeEnabled(false); | 399 mVrDaydreamApi.setVrModeEnabled(false); |
378 mLastVRExit = SystemClock.uptimeMillis(); | 400 mLastVRExit = SystemClock.uptimeMillis(); |
379 } | 401 } |
380 mActivity.setRequestedOrientation(mRestoreOrientation); | 402 mActivity.setRequestedOrientation(mRestoreOrientation); |
381 mVrShell.pause(); | 403 mVrShell.pause(); |
382 removeVrViews(); | 404 removeVrViews(); |
383 clearVrModeWindowFlags(); | 405 clearVrModeWindowFlags(); |
(...skipping 13 matching lines...) Expand all Loading... |
397 return false; | 419 return false; |
398 } | 420 } |
399 | 421 |
400 try { | 422 try { |
401 Constructor<?> mVrCoreVersionCheckerConstructor = | 423 Constructor<?> mVrCoreVersionCheckerConstructor = |
402 mVrCoreVersionCheckerClass.getConstructor(); | 424 mVrCoreVersionCheckerClass.getConstructor(); |
403 mVrCoreVersionChecker = | 425 mVrCoreVersionChecker = |
404 (VrCoreVersionChecker) mVrCoreVersionCheckerConstructor.newI
nstance(); | 426 (VrCoreVersionChecker) mVrCoreVersionCheckerConstructor.newI
nstance(); |
405 } catch (InstantiationException | IllegalAccessException | IllegalArgume
ntException | 427 } catch (InstantiationException | IllegalAccessException | IllegalArgume
ntException |
406 | InvocationTargetException | NoSuchMethodException e) { | 428 | InvocationTargetException | NoSuchMethodException e) { |
407 Log.e(TAG, "Unable to instantiate VrCoreVersionChecker", e); | 429 Log.d(TAG, "Unable to instantiate VrCoreVersionChecker", e); |
408 return false; | 430 return false; |
409 } | 431 } |
410 return mVrCoreVersionChecker.isVrCoreCompatible(); | 432 return mVrCoreVersionChecker.isVrCoreCompatible(); |
411 } | 433 } |
412 | 434 |
413 private boolean createVrDaydreamApi() { | 435 private boolean createVrDaydreamApi() { |
414 if (!mVrAvailable) return false; | |
415 | |
416 try { | 436 try { |
417 Constructor<?> vrPrivateApiConstructor = | 437 Constructor<?> vrPrivateApiConstructor = |
418 mVrDaydreamApiClass.getConstructor(Activity.class); | 438 mVrDaydreamApiClass.getConstructor(Activity.class); |
419 mVrDaydreamApi = (VrDaydreamApi) vrPrivateApiConstructor.newInstance
(mActivity); | 439 mVrDaydreamApi = (VrDaydreamApi) vrPrivateApiConstructor.newInstance
(mActivity); |
420 } catch (InstantiationException | IllegalAccessException | IllegalArgume
ntException | 440 } catch (InstantiationException | IllegalAccessException | IllegalArgume
ntException |
421 | InvocationTargetException | NoSuchMethodException e) { | 441 | InvocationTargetException | NoSuchMethodException | SecurityEx
ception e) { |
422 Log.e(TAG, "Unable to instantiate VrDaydreamApi", e); | 442 Log.d(TAG, "Unable to instantiate VrDaydreamApi", e); |
423 return false; | 443 return false; |
424 } | 444 } |
425 return true; | 445 return true; |
426 } | 446 } |
427 | 447 |
428 private boolean createVrShell() { | 448 private boolean createVrShell() { |
429 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); | 449 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); |
430 StrictMode.allowThreadDiskWrites(); | 450 StrictMode.allowThreadDiskWrites(); |
431 try { | 451 try { |
432 Constructor<?> vrShellConstructor = mVrShellClass.getConstructor(Act
ivity.class); | 452 Constructor<?> vrShellConstructor = mVrShellClass.getConstructor(Act
ivity.class); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
514 if (mVrShellEnabled == null) { | 534 if (mVrShellEnabled == null) { |
515 if (!LibraryLoader.isInitialized()) { | 535 if (!LibraryLoader.isInitialized()) { |
516 return false; | 536 return false; |
517 } | 537 } |
518 mVrShellEnabled = ChromeFeatureList.isEnabled(ChromeFeatureList.VR_S
HELL); | 538 mVrShellEnabled = ChromeFeatureList.isEnabled(ChromeFeatureList.VR_S
HELL); |
519 } | 539 } |
520 return mVrShellEnabled; | 540 return mVrShellEnabled; |
521 } | 541 } |
522 | 542 |
523 /** | 543 /** |
524 * @return Whether or not VR Shell is currently enabled. | |
525 */ | |
526 public boolean isVrInitialized() { | |
527 return mVrDaydreamApi != null; | |
528 } | |
529 | |
530 /** | |
531 * @return Pointer to the native VrShellDelegate object. | 544 * @return Pointer to the native VrShellDelegate object. |
532 */ | 545 */ |
533 @CalledByNative | 546 @CalledByNative |
534 private long getNativePointer() { | 547 private long getNativePointer() { |
535 return mNativeVrShellDelegate; | 548 return mNativeVrShellDelegate; |
536 } | 549 } |
537 | 550 |
538 private native long nativeInit(); | 551 private native long nativeInit(); |
| 552 private native void nativeSetPresentResult(long nativeVrShellDelegate, boole
an result); |
539 } | 553 } |
OLD | NEW |