blob: 0c3f091c3aa5000b15df6f63bcb5becfc2f45e9e [file]
// Copyright 2016 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 "remoting/client/jni/jni_display_handler.h"
#include "base/android/jni_android.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/stl_util.h"
#include "jni/Display_jni.h"
#include "remoting/client/jni/chromoting_jni_runtime.h"
#include "remoting/client/jni/jni_client.h"
using base::android::JavaParamRef;
namespace {
const int kBytesPerPixel = 4;
}
namespace remoting {
JniDisplayHandler::JniDisplayHandler(
scoped_refptr<base::SingleThreadTaskRunner> display_runner,
base::android::ScopedJavaGlobalRef<jobject> java_display)
: display_runner_(display_runner),
java_display_(java_display),
weak_factory_(this) {}
JniDisplayHandler::~JniDisplayHandler() {
DCHECK(display_runner_->BelongsToCurrentThread());
}
// static
base::android::ScopedJavaLocalRef<jobject> JniDisplayHandler::NewBitmap(
int width,
int height) {
JNIEnv* env = base::android::AttachCurrentThread();
return Java_Display_newBitmap(env, width, height);
}
void JniDisplayHandler::UpdateFrameBitmap(
base::android::ScopedJavaGlobalRef<jobject> bitmap) {
DCHECK(display_runner_->BelongsToCurrentThread());
JNIEnv* env = base::android::AttachCurrentThread();
Java_Display_setVideoFrame(env, java_display_.obj(), bitmap.obj());
}
void JniDisplayHandler::UpdateCursorShape(
const protocol::CursorShapeInfo& cursor_shape) {
DCHECK(display_runner_->BelongsToCurrentThread());
// const_cast<> is safe as long as the Java updateCursorShape() method copies
// the data out of the buffer without mutating it, and doesn't keep any
// reference to the buffer afterwards. Unfortunately, there seems to be no way
// to create a read-only ByteBuffer from a pointer-to-const.
char* data = string_as_array(const_cast<std::string*>(&cursor_shape.data()));
int cursor_total_bytes =
cursor_shape.width() * cursor_shape.height() * kBytesPerPixel;
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> buffer(
env, env->NewDirectByteBuffer(data, cursor_total_bytes));
Java_Display_updateCursorShape(
env, java_display_.obj(), cursor_shape.width(), cursor_shape.height(),
cursor_shape.hotspot_x(), cursor_shape.hotspot_y(), buffer.obj());
}
void JniDisplayHandler::RedrawCanvas() {
DCHECK(display_runner_->BelongsToCurrentThread());
JNIEnv* env = base::android::AttachCurrentThread();
Java_Display_redrawGraphicsInternal(env, java_display_.obj());
}
base::WeakPtr<JniDisplayHandler> JniDisplayHandler::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
// static
bool JniDisplayHandler::RegisterJni(JNIEnv* env) {
return RegisterNativesImpl(env);
}
void JniDisplayHandler::Destroy(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& caller) {
if (display_runner_->BelongsToCurrentThread()) {
delete this;
} else {
display_runner_->DeleteSoon(FROM_HERE, this);
}
}
void JniDisplayHandler::ScheduleRedraw(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& caller) {
display_runner_->PostTask(
FROM_HERE, base::Bind(&JniDisplayHandler::RedrawCanvas, GetWeakPtr()));
}
static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& caller) {
return reinterpret_cast<intptr_t>(new JniDisplayHandler(
ChromotingJniRuntime::GetInstance()->display_task_runner(),
base::android::ScopedJavaGlobalRef<jobject>(env, caller)));
}
} // namespace remoting