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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/android/vr/vr_shell_delegate.h"
6 
7 #include <utility>
8 
9 #include "base/android/jni_android.h"
10 #include "base/bind.h"
11 #include "chrome/android/features/vr/jni_headers/VrShellDelegate_jni.h"
12 #include "chrome/browser/android/vr/vr_shell.h"
13 #include "chrome/browser/android/vr/vrcore_install_helper.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/component_updater/vr_assets_component_installer.h"
16 #include "chrome/browser/vr/assets_loader.h"
17 #include "content/public/browser/browser_xr_runtime.h"
18 #include "content/public/browser/xr_runtime_manager.h"
19 #include "device/vr/android/gvr/gvr_delegate_provider_factory.h"
20 #include "device/vr/android/gvr/gvr_device.h"
21 #include "device/vr/buildflags/buildflags.h"
22 #include "device/vr/public/mojom/vr_service.mojom.h"
23 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
24 
25 using base::android::AttachCurrentThread;
26 using base::android::JavaParamRef;
27 using base::android::JavaRef;
28 using base::android::ScopedJavaLocalRef;
29 
30 namespace vr {
31 
32 namespace {
33 
34 class VrShellDelegateProviderFactory
35     : public device::GvrDelegateProviderFactory {
36  public:
37   VrShellDelegateProviderFactory() = default;
38   ~VrShellDelegateProviderFactory() override = default;
39   device::GvrDelegateProvider* CreateGvrDelegateProvider() override;
40 
41  private:
42   DISALLOW_COPY_AND_ASSIGN(VrShellDelegateProviderFactory);
43 };
44 
45 device::GvrDelegateProvider*
CreateGvrDelegateProvider()46 VrShellDelegateProviderFactory::CreateGvrDelegateProvider() {
47   return VrShellDelegate::CreateVrShellDelegate();
48 }
49 
50 }  // namespace
51 
VrShellDelegate(JNIEnv * env,jobject obj)52 VrShellDelegate::VrShellDelegate(JNIEnv* env, jobject obj)
53     : task_runner_(base::ThreadTaskRunnerHandle::Get()) {
54   DVLOG(1) << __FUNCTION__ << "=" << this;
55   j_vr_shell_delegate_.Reset(env, obj);
56 }
57 
~VrShellDelegate()58 VrShellDelegate::~VrShellDelegate() {
59   DVLOG(1) << __FUNCTION__ << "=" << this;
60   device::GvrDevice* gvr_device = GetGvrDevice();
61   if (gvr_device)
62     gvr_device->OnExitPresent();
63   if (!on_present_result_callback_.is_null())
64     std::move(on_present_result_callback_).Run(false);
65 }
66 
CreateVrShellDelegate()67 device::GvrDelegateProvider* VrShellDelegate::CreateVrShellDelegate() {
68   JNIEnv* env = AttachCurrentThread();
69   ScopedJavaLocalRef<jobject> jdelegate = Java_VrShellDelegate_getInstance(env);
70   if (!jdelegate.is_null())
71     return GetNativeVrShellDelegate(env, jdelegate);
72   return nullptr;
73 }
74 
GetNativeVrShellDelegate(JNIEnv * env,const JavaRef<jobject> & jdelegate)75 VrShellDelegate* VrShellDelegate::GetNativeVrShellDelegate(
76     JNIEnv* env,
77     const JavaRef<jobject>& jdelegate) {
78   return reinterpret_cast<VrShellDelegate*>(
79       Java_VrShellDelegate_getNativePointer(env, jdelegate));
80 }
81 
SetDelegate(VrShell * vr_shell)82 void VrShellDelegate::SetDelegate(VrShell* vr_shell) {
83   vr_shell_ = vr_shell;
84 
85   if (pending_successful_present_request_) {
86     CHECK(!on_present_result_callback_.is_null());
87     pending_successful_present_request_ = false;
88     std::move(on_present_result_callback_).Run(true);
89   }
90 }
91 
RemoveDelegate()92 void VrShellDelegate::RemoveDelegate() {
93   vr_shell_ = nullptr;
94   if (pending_successful_present_request_) {
95     CHECK(!on_present_result_callback_.is_null());
96     pending_successful_present_request_ = false;
97     std::move(on_present_result_callback_).Run(false);
98   }
99 
100   device::GvrDevice* gvr_device = GetGvrDevice();
101   if (gvr_device)
102     gvr_device->OnExitPresent();
103 }
104 
SetPresentResult(JNIEnv * env,const JavaParamRef<jobject> & obj,jboolean success)105 void VrShellDelegate::SetPresentResult(JNIEnv* env,
106                                        const JavaParamRef<jobject>& obj,
107                                        jboolean success) {
108   CHECK(!on_present_result_callback_.is_null());
109   std::move(on_present_result_callback_).Run(static_cast<bool>(success));
110 }
111 
OnPresentResult(device::mojom::VRDisplayInfoPtr display_info,device::mojom::XRRuntimeSessionOptionsPtr options,base::OnceCallback<void (device::mojom::XRSessionPtr)> callback,bool success)112 void VrShellDelegate::OnPresentResult(
113     device::mojom::VRDisplayInfoPtr display_info,
114     device::mojom::XRRuntimeSessionOptionsPtr options,
115     base::OnceCallback<void(device::mojom::XRSessionPtr)> callback,
116     bool success) {
117   DVLOG(1) << __FUNCTION__ << ": success=" << success;
118   DCHECK(options);
119 
120   DVLOG(3) << __func__ << ": options->required_features.size()="
121            << options->required_features.size()
122            << ", options->optional_features.size()="
123            << options->optional_features.size();
124 
125   if (!success) {
126     std::move(callback).Run(nullptr);
127     return;
128   }
129 
130   if (!vr_shell_) {
131     // We have to wait until the GL thread is ready since we have to get the
132     // XRPresentationClient.
133     pending_successful_present_request_ = true;
134     on_present_result_callback_ = base::BindOnce(
135         &VrShellDelegate::OnPresentResult, base::Unretained(this),
136         std::move(display_info), std::move(options), std::move(callback));
137     return;
138   }
139 
140   DVLOG(1) << __FUNCTION__ << ": connecting presenting service";
141   request_present_response_callback_ = std::move(callback);
142   vr_shell_->ConnectPresentingService(std::move(display_info),
143                                       std::move(options));
144 }
145 
SendRequestPresentReply(device::mojom::XRSessionPtr session)146 void VrShellDelegate::SendRequestPresentReply(
147     device::mojom::XRSessionPtr session) {
148   DVLOG(1) << __FUNCTION__;
149   if (!request_present_response_callback_) {
150     DLOG(ERROR) << __FUNCTION__ << ": ERROR: no callback";
151     return;
152   }
153 
154   std::move(request_present_response_callback_).Run(std::move(session));
155 }
156 
OnPause(JNIEnv * env,const JavaParamRef<jobject> & obj)157 void VrShellDelegate::OnPause(JNIEnv* env, const JavaParamRef<jobject>& obj) {
158   if (vr_shell_)
159     return;
160   device::GvrDevice* gvr_device = GetGvrDevice();
161   if (gvr_device)
162     gvr_device->PauseTracking();
163 }
164 
OnResume(JNIEnv * env,const JavaParamRef<jobject> & obj)165 void VrShellDelegate::OnResume(JNIEnv* env, const JavaParamRef<jobject>& obj) {
166   if (vr_shell_)
167     return;
168   device::GvrDevice* gvr_device = GetGvrDevice();
169   if (gvr_device)
170     gvr_device->ResumeTracking();
171 }
172 
Destroy(JNIEnv * env,const JavaParamRef<jobject> & obj)173 void VrShellDelegate::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
174   delete this;
175 }
176 
ShouldDisableGvrDevice()177 bool VrShellDelegate::ShouldDisableGvrDevice() {
178   return VrCoreInstallHelper::VrSupportNeedsUpdate();
179 }
180 
StartWebXRPresentation(device::mojom::VRDisplayInfoPtr display_info,device::mojom::XRRuntimeSessionOptionsPtr options,base::OnceCallback<void (device::mojom::XRSessionPtr)> callback)181 void VrShellDelegate::StartWebXRPresentation(
182     device::mojom::VRDisplayInfoPtr display_info,
183     device::mojom::XRRuntimeSessionOptionsPtr options,
184     base::OnceCallback<void(device::mojom::XRSessionPtr)> callback) {
185   if (!on_present_result_callback_.is_null() ||
186       !request_present_response_callback_.is_null()) {
187     // Can only handle one request at a time. This is also extremely unlikely to
188     // happen in practice.
189     std::move(callback).Run(nullptr);
190     return;
191   }
192 
193   on_present_result_callback_ = base::BindOnce(
194       &VrShellDelegate::OnPresentResult, base::Unretained(this),
195       std::move(display_info), std::move(options), std::move(callback));
196 
197   // If/When VRShell is ready for use it will call SetPresentResult.
198   JNIEnv* env = AttachCurrentThread();
199   Java_VrShellDelegate_presentRequested(env, j_vr_shell_delegate_);
200 }
201 
ExitWebVRPresent()202 void VrShellDelegate::ExitWebVRPresent() {
203   JNIEnv* env = AttachCurrentThread();
204   Java_VrShellDelegate_exitWebVRPresent(env, j_vr_shell_delegate_);
205   device::GvrDevice* gvr_device = GetGvrDevice();
206   if (gvr_device)
207     gvr_device->OnExitPresent();
208 }
209 
GetGvrDevice()210 device::GvrDevice* VrShellDelegate::GetGvrDevice() {
211   return device::GvrDelegateProviderFactory::GetDevice();
212 }
213 
214 // ----------------------------------------------------------------------------
215 // Native JNI methods
216 // ----------------------------------------------------------------------------
217 
JNI_VrShellDelegate_Init(JNIEnv * env,const JavaParamRef<jobject> & obj)218 jlong JNI_VrShellDelegate_Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
219   return reinterpret_cast<intptr_t>(new VrShellDelegate(env, obj));
220 }
221 
JNI_VrShellDelegate_OnLibraryAvailable(JNIEnv * env)222 static void JNI_VrShellDelegate_OnLibraryAvailable(JNIEnv* env) {
223   device::GvrDelegateProviderFactory::Install(
224       std::make_unique<VrShellDelegateProviderFactory>());
225 }
226 
JNI_VrShellDelegate_RegisterVrAssetsComponent(JNIEnv * env)227 static void JNI_VrShellDelegate_RegisterVrAssetsComponent(JNIEnv* env) {
228   component_updater::RegisterVrAssetsComponent(
229       g_browser_process->component_updater());
230 }
231 
232 }  // namespace vr
233