// Copyright 2018 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 "content/browser/android/select_popup.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_view_android.h" #include "content/public/android/content_jni_headers/SelectPopup_jni.h" #include "content/public/browser/render_frame_host.h" #include "content/public/common/menu_item.h" #include "content/public/common/use_zoom_for_dsf_policy.h" #include "ui/gfx/geometry/rect_f.h" using base::android::AttachCurrentThread; using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; namespace content { namespace { // Describes the type and enabled state of a select popup item. // // A Java counterpart will be generated for this enum. // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content.browser.input enum PopupItemType { // Popup item is of type group POPUP_ITEM_TYPE_GROUP, // Popup item is disabled POPUP_ITEM_TYPE_DISABLED, // Popup item is enabled POPUP_ITEM_TYPE_ENABLED, }; } // namespace SelectPopup::SelectPopup(WebContentsImpl* web_contents) : web_contents_(web_contents) { JNIEnv* env = AttachCurrentThread(); java_obj_ = JavaObjectWeakGlobalRef( env, Java_SelectPopup_create(env, web_contents_->GetJavaWebContents(), reinterpret_cast(this))); } SelectPopup::~SelectPopup() { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef j_obj = java_obj_.get(env); if (j_obj.is_null()) return; Java_SelectPopup_onNativeDestroyed(env, j_obj); } void SelectPopup::ShowMenu(RenderFrameHost* frame, const gfx::Rect& bounds, const std::vector& items, int selected_item, bool multiple, bool right_aligned) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef j_obj = java_obj_.get(env); if (j_obj.is_null()) return; // For multi-select list popups we find the list of previous selections by // iterating through the items. But for single selection popups we take the // given |selected_item| as is. ScopedJavaLocalRef selected_array; if (multiple) { std::unique_ptr native_selected_array(new jint[items.size()]); size_t selected_count = 0; for (size_t i = 0; i < items.size(); ++i) { if (items[i].checked) native_selected_array[selected_count++] = i; } selected_array = ScopedJavaLocalRef(env, env->NewIntArray(selected_count)); env->SetIntArrayRegion(selected_array.obj(), 0, selected_count, native_selected_array.get()); } else { selected_array = ScopedJavaLocalRef(env, env->NewIntArray(1)); jint value = selected_item; env->SetIntArrayRegion(selected_array.obj(), 0, 1, &value); } ScopedJavaLocalRef enabled_array(env, env->NewIntArray(items.size())); std::vector labels; labels.reserve(items.size()); for (size_t i = 0; i < items.size(); ++i) { labels.push_back(items[i].label); jint enabled = (items[i].type == MenuItem::GROUP ? POPUP_ITEM_TYPE_GROUP : (items[i].enabled ? POPUP_ITEM_TYPE_ENABLED : POPUP_ITEM_TYPE_DISABLED)); env->SetIntArrayRegion(enabled_array.obj(), i, 1, &enabled); } ScopedJavaLocalRef items_array( base::android::ToJavaArrayOfStrings(env, labels)); ui::ViewAndroid* view = web_contents_->GetNativeView(); popup_view_ = view->AcquireAnchorView(); const ScopedJavaLocalRef popup_view = popup_view_.view(); if (popup_view.is_null()) return; // |bounds| is in physical pixels if --use-zoom-for-dsf is enabled. Otherwise, // it is in DIP pixels. gfx::RectF bounds_dip = gfx::RectF(bounds); if (IsUseZoomForDSFEnabled()) bounds_dip.Scale(1 / web_contents_->GetNativeView()->GetDipScale()); view->SetAnchorRect(popup_view, bounds_dip); Java_SelectPopup_show(env, j_obj, popup_view, reinterpret_cast(frame), items_array, enabled_array, multiple, selected_array, right_aligned); } void SelectPopup::HideMenu() { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef j_obj = java_obj_.get(env); if (!j_obj.is_null()) Java_SelectPopup_hideWithoutCancel(env, j_obj); popup_view_.Reset(); } void SelectPopup::SelectMenuItems(JNIEnv* env, const JavaParamRef& obj, jlong selectPopupSourceFrame, const JavaParamRef& indices) { RenderFrameHostImpl* rfhi = reinterpret_cast(selectPopupSourceFrame); DCHECK(rfhi); if (indices == NULL) { rfhi->DidCancelPopupMenu(); return; } std::vector selected_indices; base::android::JavaIntArrayToIntVector(env, indices, &selected_indices); rfhi->DidSelectPopupMenuItems(selected_indices); } } // namespace content