| // Copyright 2015 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 "ui/platform_window/android/platform_window_android.h" |
| |
| #include <android/input.h> |
| #include <android/native_window_jni.h> |
| |
| #include "base/android/context_utils.h" |
| #include "base/android/jni_android.h" |
| #include "jni/PlatformWindowAndroid_jni.h" |
| #include "ui/events/event.h" |
| #include "ui/events/keycodes/keyboard_code_conversion_android.h" |
| #include "ui/gfx/geometry/point.h" |
| #include "ui/platform_window/platform_window_delegate.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| ui::EventType MotionEventActionToEventType(jint action) { |
| switch (action) { |
| case AMOTION_EVENT_ACTION_DOWN: |
| case AMOTION_EVENT_ACTION_POINTER_DOWN: |
| return ui::ET_TOUCH_PRESSED; |
| case AMOTION_EVENT_ACTION_UP: |
| case AMOTION_EVENT_ACTION_POINTER_UP: |
| return ui::ET_TOUCH_RELEASED; |
| case AMOTION_EVENT_ACTION_MOVE: |
| return ui::ET_TOUCH_MOVED; |
| case AMOTION_EVENT_ACTION_CANCEL: |
| return ui::ET_TOUCH_CANCELLED; |
| 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 ui::ET_UNKNOWN; |
| } |
| |
| } // namespace |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // PlatformWindowAndroid, public: |
| |
| // static |
| bool PlatformWindowAndroid::Register(JNIEnv* env) { |
| return RegisterNativesImpl(env); |
| } |
| |
| PlatformWindowAndroid::PlatformWindowAndroid(PlatformWindowDelegate* delegate) |
| : delegate_(delegate), |
| window_(NULL), |
| id_generator_(0), |
| weak_factory_(this) { |
| } |
| |
| PlatformWindowAndroid::~PlatformWindowAndroid() { |
| if (window_) |
| ReleaseWindow(); |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| ScopedJavaLocalRef<jobject> scoped_obj = |
| java_platform_window_android_.get(env); |
| if (!scoped_obj.is_null()) { |
| Java_PlatformWindowAndroid_detach(env, scoped_obj.obj()); |
| } |
| } |
| |
| void PlatformWindowAndroid::Destroy(JNIEnv* env, |
| const JavaParamRef<jobject>& obj) { |
| delegate_->OnClosed(); |
| } |
| |
| void PlatformWindowAndroid::SurfaceCreated( |
| JNIEnv* env, |
| const JavaParamRef<jobject>& obj, |
| const JavaParamRef<jobject>& jsurface, |
| float device_pixel_ratio) { |
| // 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_, device_pixel_ratio); |
| } |
| |
| void PlatformWindowAndroid::SurfaceDestroyed(JNIEnv* env, |
| const JavaParamRef<jobject>& obj) { |
| DCHECK(window_); |
| delegate_->OnAcceleratedWidgetDestroyed(); |
| ReleaseWindow(); |
| } |
| |
| void PlatformWindowAndroid::SurfaceSetSize(JNIEnv* env, |
| const JavaParamRef<jobject>& obj, |
| jint width, |
| jint height, |
| jfloat density) { |
| size_ = gfx::Size(static_cast<int>(width), static_cast<int>(height)); |
| delegate_->OnBoundsChanged(gfx::Rect(size_)); |
| } |
| |
| bool PlatformWindowAndroid::TouchEvent(JNIEnv* env, |
| const JavaParamRef<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) { |
| ui::EventType event_type = MotionEventActionToEventType(masked_action); |
| if (event_type == ui::ET_UNKNOWN) |
| return false; |
| ui::TouchEvent touch( |
| event_type, gfx::Point(), ui::EF_NONE, pointer_id, |
| base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms), |
| touch_major, touch_minor, orientation, pressure); |
| touch.set_location_f(gfx::PointF(x, y)); |
| touch.set_root_location_f(gfx::PointF(x, y)); |
| delegate_->DispatchEvent(&touch); |
| return true; |
| } |
| |
| bool PlatformWindowAndroid::KeyEvent(JNIEnv* env, |
| const JavaParamRef<jobject>& obj, |
| bool pressed, |
| jint key_code, |
| jint unicode_character) { |
| ui::KeyEvent key_event(pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED, |
| ui::KeyboardCodeFromAndroidKeyCode(key_code), 0); |
| delegate_->DispatchEvent(&key_event); |
| if (pressed && unicode_character) { |
| ui::KeyEvent char_event(unicode_character, |
| ui::KeyboardCodeFromAndroidKeyCode(key_code), 0); |
| delegate_->DispatchEvent(&char_event); |
| } |
| return true; |
| } |
| |
| void PlatformWindowAndroid::ReleaseWindow() { |
| ANativeWindow_release(window_); |
| window_ = NULL; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // PlatformWindowAndroid, PlatformWindow implementation: |
| |
| void PlatformWindowAndroid::Show() { |
| if (!java_platform_window_android_.is_empty()) |
| return; |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| java_platform_window_android_ = JavaObjectWeakGlobalRef( |
| env, Java_PlatformWindowAndroid_createForActivity( |
| env, base::android::GetApplicationContext(), |
| reinterpret_cast<jlong>(this), |
| reinterpret_cast<jlong>(&platform_ime_controller_)).obj()); |
| } |
| |
| void PlatformWindowAndroid::Hide() { |
| // Nothing to do. View is always visible. |
| } |
| |
| void PlatformWindowAndroid::Close() { |
| delegate_->OnCloseRequest(); |
| } |
| |
| void PlatformWindowAndroid::SetBounds(const gfx::Rect& bounds) { |
| NOTIMPLEMENTED(); |
| } |
| |
| gfx::Rect PlatformWindowAndroid::GetBounds() { |
| return gfx::Rect(size_); |
| } |
| |
| void PlatformWindowAndroid::SetTitle(const base::string16& title) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::SetCapture() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::ReleaseCapture() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::ToggleFullscreen() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::Maximize() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::Minimize() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::Restore() { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::SetCursor(PlatformCursor cursor) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::MoveCursorTo(const gfx::Point& location) { |
| NOTIMPLEMENTED(); |
| } |
| |
| void PlatformWindowAndroid::ConfineCursorToBounds(const gfx::Rect& bounds) { |
| NOTIMPLEMENTED(); |
| } |
| |
| PlatformImeController* PlatformWindowAndroid::GetPlatformImeController() { |
| return &platform_ime_controller_; |
| } |
| |
| } // namespace ui |