blob: c139dcee787128fefea6dd80efb8dfb3c5e2e58c [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/webxr/android/arcore_java_utils.h"
#include <memory>
#include <utility>
#include "base/android/jni_string.h"
#include "components/webxr/android/ar_jni_headers/ArCoreJavaUtils_jni.h"
#include "components/webxr/android/webxr_utils.h"
#include "device/vr/android/arcore/arcore_shim.h"
#include "gpu/ipc/common/gpu_surface_tracker.h"
#include "ui/android/window_android.h"
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
namespace webxr {
ArCoreJavaUtils::ArCoreJavaUtils(
webxr::ArCompositorDelegateProvider compositor_delegate_provider)
: compositor_delegate_provider_(compositor_delegate_provider) {
JNIEnv* env = AttachCurrentThread();
if (!env)
return;
ScopedJavaLocalRef<jobject> j_arcore_java_utils =
Java_ArCoreJavaUtils_create(env, (jlong)this);
if (j_arcore_java_utils.is_null())
return;
j_arcore_java_utils_.Reset(j_arcore_java_utils);
}
ArCoreJavaUtils::~ArCoreJavaUtils() {
JNIEnv* env = AttachCurrentThread();
Java_ArCoreJavaUtils_onNativeDestroy(env, j_arcore_java_utils_);
}
void ArCoreJavaUtils::RequestArSession(
int render_process_id,
int render_frame_id,
bool use_overlay,
bool can_render_dom_content,
device::SurfaceReadyCallback ready_callback,
device::SurfaceTouchCallback touch_callback,
device::SurfaceDestroyedCallback destroyed_callback) {
DVLOG(1) << __func__;
JNIEnv* env = AttachCurrentThread();
surface_ready_callback_ = std::move(ready_callback);
surface_touch_callback_ = std::move(touch_callback);
surface_destroyed_callback_ = std::move(destroyed_callback);
Java_ArCoreJavaUtils_startSession(
env, j_arcore_java_utils_, compositor_delegate_provider_.GetJavaObject(),
webxr::GetJavaWebContents(render_process_id, render_frame_id),
use_overlay, can_render_dom_content);
}
void ArCoreJavaUtils::EndSession() {
DVLOG(1) << __func__;
JNIEnv* env = AttachCurrentThread();
Java_ArCoreJavaUtils_endSession(env, j_arcore_java_utils_);
}
void ArCoreJavaUtils::OnDrawingSurfaceReady(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jobject>& surface,
const base::android::JavaParamRef<jobject>& java_root_window,
int rotation,
int width,
int height) {
DVLOG(1) << __func__ << ": width=" << width << " height=" << height
<< " rotation=" << rotation;
gfx::AcceleratedWidget window =
ANativeWindow_fromSurface(base::android::AttachCurrentThread(), surface);
gpu::SurfaceHandle surface_handle =
gpu::GpuSurfaceTracker::Get()->AddSurfaceForNativeWidget(
gpu::GpuSurfaceTracker::SurfaceRecord(
window, surface, /*can_be_used_with_surface_control=*/false));
ui::WindowAndroid* root_window =
ui::WindowAndroid::FromJavaWindowAndroid(java_root_window);
display::Display::Rotation display_rotation =
static_cast<display::Display::Rotation>(rotation);
surface_ready_callback_.Run(window, surface_handle, root_window,
display_rotation, {width, height});
}
void ArCoreJavaUtils::OnDrawingSurfaceTouch(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
bool primary,
bool touching,
int32_t pointer_id,
float x,
float y) {
DVLOG(3) << __func__ << ": pointer_id=" << pointer_id
<< " primary=" << primary << " touching=" << touching;
surface_touch_callback_.Run(primary, touching, pointer_id, {x, y});
}
void ArCoreJavaUtils::OnDrawingSurfaceDestroyed(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
DVLOG(1) << __func__ << ":::";
if (surface_destroyed_callback_) {
std::move(surface_destroyed_callback_).Run();
}
}
bool ArCoreJavaUtils::EnsureLoaded() {
DCHECK(device::IsArCoreSupported());
JNIEnv* env = AttachCurrentThread();
// TODO(crbug.com/884780): Allow loading the ARCore shim by name instead of by
// absolute path.
ScopedJavaLocalRef<jstring> java_path =
Java_ArCoreJavaUtils_getArCoreShimLibraryPath(env);
// Crash in debug builds if `java_path` is a null pointer but handle this
// situation in release builds. This is done by design - the `java_path` will
// be null only if there was a regression introduced to our gn/gni files w/o
// causing a build break. In release builds, this approach will result in the
// site not being able to request an AR session.
DCHECK(java_path)
<< "Unable to find path to ARCore SDK library - please ensure that "
"loadable_modules and secondary_abi_loadable_modules are set "
"correctly when building";
if (!java_path) {
LOG(ERROR) << "Unable to find path to ARCore SDK library";
return false;
}
return device::LoadArCoreSdk(
base::android::ConvertJavaStringToUTF8(env, java_path));
}
ScopedJavaLocalRef<jobject> ArCoreJavaUtils::GetApplicationContext() {
JNIEnv* env = AttachCurrentThread();
return Java_ArCoreJavaUtils_getApplicationContext(env);
}
} // namespace webxr