// Copyright (c) 2012 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 "webkit/glue/fling_animator_impl_android.h" #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" #include "base/logging.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebGestureCurveTarget.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebPoint.h" #include "ui/gfx/vector2d.h" using base::android::AttachCurrentThread; using base::android::CheckException; using base::android::GetApplicationContext; using base::android::GetClass; using base::android::MethodID; using base::android::ScopedJavaLocalRef; namespace webkit_glue { FlingAnimatorImpl::FlingAnimatorImpl() : is_active_(false) { // hold the global reference of the Java objects. JNIEnv* env = AttachCurrentThread(); DCHECK(env); ScopedJavaLocalRef cls(GetClass(env, "android/widget/OverScroller")); jmethodID constructor = MethodID::Get( env, cls.obj(), "", "(Landroid/content/Context;)V"); ScopedJavaLocalRef tmp(env, env->NewObject(cls.obj(), constructor, GetApplicationContext())); DCHECK(tmp.obj()); java_scroller_.Reset(tmp); fling_method_id_ = MethodID::Get( env, cls.obj(), "fling", "(IIIIIIII)V"); abort_method_id_ = MethodID::Get( env, cls.obj(), "abortAnimation", "()V"); compute_method_id_ = MethodID::Get( env, cls.obj(), "computeScrollOffset", "()Z"); getX_method_id_ = MethodID::Get( env, cls.obj(), "getCurrX", "()I"); getY_method_id_ = MethodID::Get( env, cls.obj(), "getCurrY", "()I"); } FlingAnimatorImpl::~FlingAnimatorImpl() { } void FlingAnimatorImpl::StartFling(const gfx::PointF& velocity) { // No bounds on the fling. See http://webkit.org/b/96403 // Instead, use the largest possible bounds for minX/maxX/minY/maxY. The // compositor will ignore any attempt to scroll beyond the end of the page. DCHECK(velocity.x() || velocity.y()); if (is_active_) CancelFling(); is_active_ = true; JNIEnv* env = AttachCurrentThread(); env->CallVoidMethod(java_scroller_.obj(), fling_method_id_, 0, 0, static_cast(velocity.x()), static_cast(velocity.y()), INT_MIN, INT_MAX, INT_MIN, INT_MAX); CheckException(env); } void FlingAnimatorImpl::CancelFling() { if (!is_active_) return; is_active_ = false; JNIEnv* env = AttachCurrentThread(); env->CallVoidMethod(java_scroller_.obj(), abort_method_id_); CheckException(env); } bool FlingAnimatorImpl::UpdatePosition() { JNIEnv* env = AttachCurrentThread(); bool result = env->CallBooleanMethod(java_scroller_.obj(), compute_method_id_); CheckException(env); return is_active_ = result; } gfx::Point FlingAnimatorImpl::GetCurrentPosition() { JNIEnv* env = AttachCurrentThread(); gfx::Point position( env->CallIntMethod(java_scroller_.obj(), getX_method_id_), env->CallIntMethod(java_scroller_.obj(), getY_method_id_)); CheckException(env); return position; } bool FlingAnimatorImpl::apply(double time, WebKit::WebGestureCurveTarget* target) { if (!UpdatePosition()) return false; gfx::Point current_position = GetCurrentPosition(); gfx::Vector2d diff(current_position - last_position_); last_position_ = current_position; WebKit::WebPoint scroll_amount(diff.x(), diff.y()); // scrollBy() could delete this curve if the animation is over, so don't touch // any member variables after making that call. target->scrollBy(scroll_amount); return true; } FlingAnimatorImpl* FlingAnimatorImpl::CreateAndroidGestureCurve( const WebKit::WebFloatPoint& velocity, const WebKit::WebSize&) { FlingAnimatorImpl* gesture_curve = new FlingAnimatorImpl(); gesture_curve->StartFling(velocity); return gesture_curve; } } // namespace webkit_glue