// 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 "ui/android/view_android.h" #include #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "cc/layers/layer.h" #include "jni/ViewAndroidDelegate_jni.h" #include "ui/android/window_android.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "url/gurl.h" namespace ui { using base::android::ConvertUTF8ToJavaString; using base::android::JavaRef; using base::android::ScopedJavaLocalRef; ViewAndroid::ScopedAnchorView::ScopedAnchorView( JNIEnv* env, const JavaRef& jview, const JavaRef& jdelegate) : view_(env, jview.obj()), delegate_(env, jdelegate.obj()) { // If there's a view, then we need a delegate to remove it. DCHECK(!jdelegate.is_null() || jview.is_null()); } ViewAndroid::ScopedAnchorView::ScopedAnchorView() { } ViewAndroid::ScopedAnchorView::ScopedAnchorView(ScopedAnchorView&& other) { view_ = other.view_; other.view_.reset(); delegate_ = other.delegate_; other.delegate_.reset(); } ViewAndroid::ScopedAnchorView& ViewAndroid::ScopedAnchorView::operator=(ScopedAnchorView&& other) { if (this != &other) { view_ = other.view_; other.view_.reset(); delegate_ = other.delegate_; other.delegate_.reset(); } return *this; } ViewAndroid::ScopedAnchorView::~ScopedAnchorView() { Reset(); } void ViewAndroid::ScopedAnchorView::Reset() { JNIEnv* env = base::android::AttachCurrentThread(); const ScopedJavaLocalRef view = view_.get(env); const ScopedJavaLocalRef delegate = delegate_.get(env); if (!view.is_null() && !delegate.is_null()) { Java_ViewAndroidDelegate_removeView(env, delegate, view); } view_.reset(); delegate_.reset(); } const base::android::ScopedJavaLocalRef ViewAndroid::ScopedAnchorView::view() const { JNIEnv* env = base::android::AttachCurrentThread(); return view_.get(env); } ViewAndroid::ViewAndroid(const JavaRef& delegate) : parent_(nullptr), delegate_(base::android::AttachCurrentThread(), delegate.obj()) {} ViewAndroid::ViewAndroid() : parent_(nullptr) {} ViewAndroid::~ViewAndroid() { RemoveFromParent(); for (std::list::iterator it = children_.begin(); it != children_.end(); it++) { DCHECK_EQ((*it)->parent_, this); (*it)->parent_ = nullptr; } } void ViewAndroid::SetDelegate(const JavaRef& delegate) { JNIEnv* env = base::android::AttachCurrentThread(); delegate_ = JavaObjectWeakGlobalRef(env, delegate); } void ViewAndroid::AddChild(ViewAndroid* child) { DCHECK(child); DCHECK(std::find(children_.begin(), children_.end(), child) == children_.end()); children_.push_back(child); if (child->parent_) child->RemoveFromParent(); child->parent_ = this; } void ViewAndroid::RemoveFromParent() { if (parent_) parent_->RemoveChild(this); } ViewAndroid::ScopedAnchorView ViewAndroid::AcquireAnchorView() { ScopedJavaLocalRef delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return ViewAndroid::ScopedAnchorView(); JNIEnv* env = base::android::AttachCurrentThread(); return ViewAndroid::ScopedAnchorView( env, Java_ViewAndroidDelegate_acquireView(env, delegate), delegate); } void ViewAndroid::SetAnchorRect(const JavaRef& anchor, const gfx::RectF& bounds) { ScopedJavaLocalRef delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return; float scale = display::Screen::GetScreen() ->GetDisplayNearestWindow(this) .device_scale_factor(); int left_margin = std::round(bounds.x() * scale); int top_margin = std::round((content_offset().y() + bounds.y()) * scale); JNIEnv* env = base::android::AttachCurrentThread(); Java_ViewAndroidDelegate_setViewPosition( env, delegate, anchor, bounds.x(), bounds.y(), bounds.width(), bounds.height(), scale, left_margin, top_margin); } ScopedJavaLocalRef ViewAndroid::GetContainerView() { ScopedJavaLocalRef delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return nullptr; JNIEnv* env = base::android::AttachCurrentThread(); return Java_ViewAndroidDelegate_getContainerView(env, delegate); } void ViewAndroid::RemoveChild(ViewAndroid* child) { DCHECK(child); DCHECK_EQ(child->parent_, this); std::list::iterator it = std::find(children_.begin(), children_.end(), child); DCHECK(it != children_.end()); children_.erase(it); child->parent_ = nullptr; } WindowAndroid* ViewAndroid::GetWindowAndroid() const { return parent_ ? parent_->GetWindowAndroid() : nullptr; } const ScopedJavaLocalRef ViewAndroid::GetViewAndroidDelegate() const { JNIEnv* env = base::android::AttachCurrentThread(); const ScopedJavaLocalRef delegate = delegate_.get(env); if (!delegate.is_null()) return delegate; return parent_ ? parent_->GetViewAndroidDelegate() : delegate; } cc::Layer* ViewAndroid::GetLayer() const { return layer_.get(); } void ViewAndroid::SetLayer(scoped_refptr layer) { layer_ = layer; } bool ViewAndroid::StartDragAndDrop(const JavaRef& jtext, const JavaRef& jimage) { ScopedJavaLocalRef delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return false; JNIEnv* env = base::android::AttachCurrentThread(); return Java_ViewAndroidDelegate_startDragAndDrop(env, delegate, jtext, jimage); } void ViewAndroid::OnBackgroundColorChanged(unsigned int color) { ScopedJavaLocalRef delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return; JNIEnv* env = base::android::AttachCurrentThread(); Java_ViewAndroidDelegate_onBackgroundColorChanged(env, delegate, color); } void ViewAndroid::OnTopControlsChanged(float top_controls_offset, float top_content_offset) { ScopedJavaLocalRef delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return; JNIEnv* env = base::android::AttachCurrentThread(); Java_ViewAndroidDelegate_onTopControlsChanged( env, delegate, top_controls_offset, top_content_offset); } void ViewAndroid::OnBottomControlsChanged(float bottom_controls_offset, float bottom_content_offset) { ScopedJavaLocalRef delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return; JNIEnv* env = base::android::AttachCurrentThread(); Java_ViewAndroidDelegate_onBottomControlsChanged( env, delegate, bottom_controls_offset, bottom_content_offset); } void ViewAndroid::StartContentIntent(const GURL& content_url, bool is_main_frame) { ScopedJavaLocalRef delegate(GetViewAndroidDelegate()); if (delegate.is_null()) return; JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef jcontent_url = ConvertUTF8ToJavaString(env, content_url.spec()); Java_ViewAndroidDelegate_onStartContentIntent(env, delegate, jcontent_url, is_main_frame); } } // namespace ui