blob: 625c8fa893e7e94a6eadfe97235323933d351f6b [file] [log] [blame]
// Copyright 2013 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 "services/native_viewport/platform_viewport_android.h"
#include <android/input.h>
#include <android/native_window_jni.h>
#include "base/android/jni_android.h"
#include "base/bind.h"
#include "jni/PlatformViewportAndroid_jni.h"
#include "mojo/converters/geometry/geometry_type_converters.h"
#include "mojo/converters/input_events/input_events_type_converters.h"
#include "mojo/public/cpp/application/connect.h"
#include "services/native_viewport/native_viewport_support.mojom.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_code_conversion_android.h"
#include "ui/gfx/point.h"
namespace native_viewport {
namespace {
mojo::EventType MotionEventActionToEventType(jint action) {
switch (action) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_POINTER_DOWN:
return mojo::EventType::POINTER_DOWN;
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_UP:
return mojo::EventType::POINTER_UP;
case AMOTION_EVENT_ACTION_MOVE:
return mojo::EventType::POINTER_MOVE;
case AMOTION_EVENT_ACTION_CANCEL:
return mojo::EventType::POINTER_CANCEL;
case AMOTION_EVENT_ACTION_OUTSIDE:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
case AMOTION_EVENT_ACTION_SCROLL:
case AMOTION_EVENT_ACTION_HOVER_ENTER:
case AMOTION_EVENT_ACTION_HOVER_EXIT:
default:
NOTIMPLEMENTED() << "Unimplemented motion action: " << action;
}
return mojo::EventType::UNKNOWN;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// PlatformViewportAndroid, public:
// static
bool PlatformViewportAndroid::Register(JNIEnv* env) {
return RegisterNativesImpl(env);
}
PlatformViewportAndroid::PlatformViewportAndroid(mojo::Shell* shell,
Delegate* delegate)
: shell_(shell),
delegate_(delegate),
window_(NULL),
id_generator_(0),
weak_factory_(this) {}
PlatformViewportAndroid::~PlatformViewportAndroid() {
if (window_)
ReleaseWindow();
JNIEnv* env = base::android::AttachCurrentThread();
if (!java_platform_viewport_android_.is_empty()) {
Java_PlatformViewportAndroid_detach(
env, java_platform_viewport_android_.get(env).obj());
} else {
Java_PlatformViewportAndroid_withdrawRequest(
env, reinterpret_cast<intptr_t>(this));
}
}
void PlatformViewportAndroid::Destroy(JNIEnv* env, jobject obj) {
delegate_->OnDestroyed();
}
void PlatformViewportAndroid::SurfaceAttached(JNIEnv* env,
jobject obj,
jobject platform_viewport) {
java_platform_viewport_android_ =
JavaObjectWeakGlobalRef(env, platform_viewport);
}
void PlatformViewportAndroid::SurfaceCreated(JNIEnv* env,
jobject obj,
jobject jsurface) {
base::android::ScopedJavaLocalRef<jobject> protector(env, jsurface);
// Note: This ensures that any local references used by
// ANativeWindow_fromSurface are released immediately. This is needed as a
// workaround for https://code.google.com/p/android/issues/detail?id=68174
{
base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
window_ = ANativeWindow_fromSurface(env, jsurface);
}
delegate_->OnAcceleratedWidgetAvailable(window_);
}
void PlatformViewportAndroid::SurfaceDestroyed(JNIEnv* env, jobject obj) {
DCHECK(window_);
delegate_->OnAcceleratedWidgetDestroyed();
ReleaseWindow();
}
void PlatformViewportAndroid::SurfaceSetSize(JNIEnv* env,
jobject obj,
jint width,
jint height,
jfloat density) {
metrics_ = mojo::ViewportMetrics::New();
metrics_->size = mojo::Size::New();
metrics_->size->width = static_cast<int>(width);
metrics_->size->height = static_cast<int>(height);
metrics_->device_pixel_ratio = density;
delegate_->OnMetricsChanged(metrics_.Clone());
}
bool PlatformViewportAndroid::TouchEvent(JNIEnv* env,
jobject obj,
jlong time_ms,
jint masked_action,
jint pointer_id,
jfloat x,
jfloat y,
jfloat pressure,
jfloat touch_major,
jfloat touch_minor,
jfloat orientation,
jfloat h_wheel,
jfloat v_wheel) {
mojo::EventPtr event(mojo::Event::New());
event->time_stamp =
(base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms))
.ToInternalValue();
event->action = MotionEventActionToEventType(masked_action);
if (event->action == mojo::EventType::UNKNOWN)
return false;
event->pointer_data = mojo::PointerData::New();
event->pointer_data->pointer_id = pointer_id;
event->pointer_data->x = x;
event->pointer_data->y = y;
event->pointer_data->screen_x = x;
event->pointer_data->screen_y = y;
event->pointer_data->pressure = pressure;
event->pointer_data->radius_major = touch_major;
event->pointer_data->radius_minor = touch_minor;
event->pointer_data->orientation = orientation;
event->pointer_data->horizontal_wheel = h_wheel;
event->pointer_data->vertical_wheel = v_wheel;
delegate_->OnEvent(event.Pass());
return true;
}
////////////////////////////////////////////////////////////////////////////////
// PlatformViewportAndroid, PlatformViewport implementation:
void PlatformViewportAndroid::Init(const gfx::Rect& bounds) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_PlatformViewportAndroid_createRequest(env,
reinterpret_cast<intptr_t>(this));
mojo::ConnectToService(shell_, "mojo:native_viewport_support",
GetProxy(&support_service_));
support_service_->CreateNewNativeWindow(
base::Bind(&PlatformViewportAndroid::Close, weak_factory_.GetWeakPtr()));
}
void PlatformViewportAndroid::Show() {
// Nothing to do. View is created visible.
}
void PlatformViewportAndroid::Hide() {
// Nothing to do. View is always visible.
}
void PlatformViewportAndroid::Close() {
// TODO(beng): close activity containing MojoView?
// TODO(beng): perform this in response to view destruction.
delegate_->OnDestroyed();
}
gfx::Size PlatformViewportAndroid::GetSize() {
return metrics_->size.To<gfx::Size>();
}
void PlatformViewportAndroid::SetBounds(const gfx::Rect& bounds) {
NOTIMPLEMENTED();
}
////////////////////////////////////////////////////////////////////////////////
// PlatformViewportAndroid, private:
void PlatformViewportAndroid::ReleaseWindow() {
ANativeWindow_release(window_);
window_ = NULL;
}
////////////////////////////////////////////////////////////////////////////////
// PlatformViewport, public:
// static
scoped_ptr<PlatformViewport> PlatformViewport::Create(mojo::Shell* shell,
Delegate* delegate) {
return scoped_ptr<PlatformViewport>(
new PlatformViewportAndroid(shell, delegate))
.Pass();
}
} // namespace native_viewport