Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/android/view_android.h" | 5 #include "ui/android/view_android.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/android/jni_android.h" | 9 #include "base/android/jni_android.h" |
| 10 #include "base/android/jni_string.h" | 10 #include "base/android/jni_string.h" |
| 11 #include "base/containers/adapters.h" | |
| 11 #include "cc/layers/layer.h" | 12 #include "cc/layers/layer.h" |
| 12 #include "jni/ViewAndroidDelegate_jni.h" | 13 #include "jni/ViewAndroidDelegate_jni.h" |
| 14 #include "ui/android/event_handler.h" | |
| 15 #include "ui/android/view_client.h" | |
| 13 #include "ui/android/window_android.h" | 16 #include "ui/android/window_android.h" |
| 14 #include "ui/display/display.h" | 17 #include "ui/base/layout.h" |
| 15 #include "ui/display/screen.h" | 18 #include "ui/events/android/motion_event_android.h" |
| 16 #include "url/gurl.h" | 19 #include "url/gurl.h" |
| 17 | 20 |
| 18 namespace ui { | 21 namespace ui { |
| 19 | 22 |
| 20 using base::android::ConvertUTF8ToJavaString; | 23 using base::android::ConvertUTF8ToJavaString; |
| 21 using base::android::JavaRef; | 24 using base::android::JavaRef; |
| 22 using base::android::ScopedJavaLocalRef; | 25 using base::android::ScopedJavaLocalRef; |
| 23 | 26 |
| 27 namespace { | |
| 28 | |
| 29 struct TouchEventSender : ViewAndroid::EventSender { | |
| 30 TouchEventSender(bool for_touch_handle) | |
| 31 : for_touch_handle_(for_touch_handle) {} | |
| 32 bool SendToView(ViewAndroid* view, | |
| 33 const MotionEventAndroid& e) const override { | |
| 34 return view->OnTouchEvent(e, for_touch_handle_); | |
| 35 } | |
| 36 | |
| 37 bool SendToClient(ViewClient* client, | |
| 38 const MotionEventAndroid& e) const override { | |
| 39 return client->OnTouchEvent(e, for_touch_handle_); | |
| 40 } | |
| 41 | |
| 42 private: | |
| 43 bool for_touch_handle_; | |
| 44 }; | |
| 45 | |
| 46 struct MouseEventSender : ViewAndroid::EventSender { | |
| 47 MouseEventSender() {} | |
| 48 bool SendToView(ViewAndroid* view, | |
| 49 const MotionEventAndroid& e) const override { | |
| 50 return view->OnMouseEvent(e); | |
| 51 } | |
| 52 | |
| 53 bool SendToClient(ViewClient* client, | |
| 54 const MotionEventAndroid& e) const override { | |
| 55 return client->OnMouseEvent(e); | |
| 56 } | |
| 57 }; | |
| 58 | |
| 59 } // namespace | |
| 60 | |
| 24 ViewAndroid::ScopedAnchorView::ScopedAnchorView( | 61 ViewAndroid::ScopedAnchorView::ScopedAnchorView( |
| 25 JNIEnv* env, | 62 JNIEnv* env, |
| 26 const JavaRef<jobject>& jview, | 63 const JavaRef<jobject>& jview, |
| 27 const JavaRef<jobject>& jdelegate) | 64 const JavaRef<jobject>& jdelegate) |
| 28 : view_(env, jview.obj()), delegate_(env, jdelegate.obj()) { | 65 : view_(env, jview.obj()), delegate_(env, jdelegate.obj()) { |
| 29 // If there's a view, then we need a delegate to remove it. | 66 // If there's a view, then we need a delegate to remove it. |
| 30 DCHECK(!jdelegate.is_null() || jview.is_null()); | 67 DCHECK(!jdelegate.is_null() || jview.is_null()); |
| 31 } | 68 } |
| 32 | 69 |
| 33 ViewAndroid::ScopedAnchorView::ScopedAnchorView() { } | 70 ViewAndroid::ScopedAnchorView::ScopedAnchorView() { } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 64 view_.reset(); | 101 view_.reset(); |
| 65 delegate_.reset(); | 102 delegate_.reset(); |
| 66 } | 103 } |
| 67 | 104 |
| 68 const base::android::ScopedJavaLocalRef<jobject> | 105 const base::android::ScopedJavaLocalRef<jobject> |
| 69 ViewAndroid::ScopedAnchorView::view() const { | 106 ViewAndroid::ScopedAnchorView::view() const { |
| 70 JNIEnv* env = base::android::AttachCurrentThread(); | 107 JNIEnv* env = base::android::AttachCurrentThread(); |
| 71 return view_.get(env); | 108 return view_.get(env); |
| 72 } | 109 } |
| 73 | 110 |
| 74 ViewAndroid::ViewAndroid(const JavaRef<jobject>& delegate) | 111 ViewAndroid::ViewAndroid(ViewClient* view_client) |
| 75 : parent_(nullptr), | 112 : parent_(nullptr), client_(view_client) {} |
| 76 delegate_(base::android::AttachCurrentThread(), delegate.obj()) {} | |
| 77 | 113 |
| 78 ViewAndroid::ViewAndroid() : parent_(nullptr) {} | 114 ViewAndroid::ViewAndroid() : ViewAndroid(nullptr) {} |
| 79 | 115 |
| 80 ViewAndroid::~ViewAndroid() { | 116 ViewAndroid::~ViewAndroid() { |
| 81 RemoveFromParent(); | 117 RemoveFromParent(); |
| 82 | 118 |
| 83 for (std::list<ViewAndroid*>::iterator it = children_.begin(); | 119 for (std::list<ViewAndroid*>::iterator it = children_.begin(); |
| 84 it != children_.end(); it++) { | 120 it != children_.end(); it++) { |
| 85 DCHECK_EQ((*it)->parent_, this); | 121 DCHECK_EQ((*it)->parent_, this); |
| 86 (*it)->parent_ = nullptr; | 122 (*it)->parent_ = nullptr; |
| 87 } | 123 } |
| 88 } | 124 } |
| 89 | 125 |
| 90 void ViewAndroid::SetDelegate(const JavaRef<jobject>& delegate) { | 126 void ViewAndroid::SetDelegate(const JavaRef<jobject>& delegate) { |
| 127 // A ViewAndroid may have its own delegate or otherwise will use the next | |
| 128 // available parent's delegate. | |
| 91 JNIEnv* env = base::android::AttachCurrentThread(); | 129 JNIEnv* env = base::android::AttachCurrentThread(); |
| 92 delegate_ = JavaObjectWeakGlobalRef(env, delegate); | 130 delegate_ = JavaObjectWeakGlobalRef(env, delegate); |
| 93 } | 131 } |
| 94 | 132 |
| 133 float ViewAndroid::GetDipScale() { | |
| 134 return ui::GetScaleFactorForNativeView(this); | |
| 135 } | |
| 136 | |
| 137 ScopedJavaLocalRef<jobject> ViewAndroid::GetEventHandler() { | |
| 138 if (!event_handler_) { | |
| 139 DCHECK(!ViewTreeHasEventHandler(this)) | |
| 140 << "Root of the ViewAndroid can have at most one handler."; | |
| 141 event_handler_.reset(new EventHandler(this)); | |
| 142 } | |
| 143 return event_handler_->GetJavaObject(); | |
| 144 } | |
| 145 | |
| 95 void ViewAndroid::AddChild(ViewAndroid* child) { | 146 void ViewAndroid::AddChild(ViewAndroid* child) { |
| 96 DCHECK(child); | 147 DCHECK(child); |
| 97 DCHECK(std::find(children_.begin(), children_.end(), child) == | 148 DCHECK(std::find(children_.begin(), children_.end(), child) == |
| 98 children_.end()); | 149 children_.end()); |
| 150 DCHECK(!ChildrenHaveEventHandler(child) || !ViewTreeHasEventHandler(this)) | |
|
Khushal
2017/03/03 23:36:07
nit: this is a bit confusing. How about:
DCHECK(!c
Jinsuk Kim
2017/03/06 04:07:34
has_event_handler() won't be enough since it only
Khushal
2017/03/07 04:17:08
Sorry I missed that. Much clearer now. Thanks.
| |
| 151 << "Only one event handler is allowed."; | |
| 99 | 152 |
| 153 // The new child goes to the top, which is the end of the list. | |
| 100 children_.push_back(child); | 154 children_.push_back(child); |
| 101 if (child->parent_) | 155 if (child->parent_) |
| 102 child->RemoveFromParent(); | 156 child->RemoveFromParent(); |
| 103 child->parent_ = this; | 157 child->parent_ = this; |
| 104 } | 158 } |
| 105 | 159 |
| 160 // static | |
| 161 bool ViewAndroid::ViewTreeHasEventHandler(ViewAndroid* view) { | |
| 162 ViewAndroid* v = view; | |
| 163 do { | |
| 164 if (v->has_event_handler()) | |
| 165 return true; | |
| 166 v = v->parent_; | |
| 167 } while (v); | |
| 168 return ChildrenHaveEventHandler(view); | |
| 169 } | |
| 170 | |
| 171 // static | |
| 172 bool ViewAndroid::ChildrenHaveEventHandler(ViewAndroid* view) { | |
| 173 if (view->has_event_handler()) | |
| 174 return true; | |
| 175 for (auto* child : view->children_) { | |
| 176 if (child->ChildrenHaveEventHandler(child)) | |
|
Khushal
2017/03/03 23:36:08
You're calling a static method on child?
And these
Jinsuk Kim
2017/03/06 04:07:34
They access non-public member/method which I'd rat
Khushal
2017/03/07 04:17:07
That should still be possible if you put it in the
Jinsuk Kim
2017/03/07 05:02:23
Sorry I still don't get it - |view->children_|, |v
Khushal
2017/03/07 06:32:05
Sorry for being unclear. I meant |ChildrenHaveEven
Khushal
2017/03/07 06:43:13
I see it now. :l Please ignore me here.
Jinsuk Kim
2017/03/08 02:16:16
Acknowledged.
| |
| 177 return true; | |
| 178 } | |
| 179 return false; | |
| 180 } | |
| 181 | |
| 182 void ViewAndroid::MoveToTop(ViewAndroid* child) { | |
| 183 DCHECK(child); | |
| 184 auto it = std::find(children_.begin(), children_.end(), child); | |
| 185 DCHECK(it != children_.end()); | |
| 186 | |
| 187 // Top element is placed at the end of the list. | |
| 188 if (*it != children_.back()) | |
| 189 children_.splice(children_.end(), children_, it); | |
| 190 } | |
| 191 | |
| 106 void ViewAndroid::RemoveFromParent() { | 192 void ViewAndroid::RemoveFromParent() { |
| 107 if (parent_) | 193 if (parent_) |
| 108 parent_->RemoveChild(this); | 194 parent_->RemoveChild(this); |
| 109 } | 195 } |
| 110 | 196 |
| 111 ViewAndroid::ScopedAnchorView ViewAndroid::AcquireAnchorView() { | 197 ViewAndroid::ScopedAnchorView ViewAndroid::AcquireAnchorView() { |
| 112 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); | 198 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); |
| 113 if (delegate.is_null()) | 199 if (delegate.is_null()) |
| 114 return ViewAndroid::ScopedAnchorView(); | 200 return ViewAndroid::ScopedAnchorView(); |
| 115 | 201 |
| 116 JNIEnv* env = base::android::AttachCurrentThread(); | 202 JNIEnv* env = base::android::AttachCurrentThread(); |
| 117 return ViewAndroid::ScopedAnchorView( | 203 return ViewAndroid::ScopedAnchorView( |
| 118 env, Java_ViewAndroidDelegate_acquireView(env, delegate), delegate); | 204 env, Java_ViewAndroidDelegate_acquireView(env, delegate), delegate); |
| 119 } | 205 } |
| 120 | 206 |
| 121 void ViewAndroid::SetAnchorRect(const JavaRef<jobject>& anchor, | 207 void ViewAndroid::SetAnchorRect(const JavaRef<jobject>& anchor, |
| 122 const gfx::RectF& bounds) { | 208 const gfx::RectF& bounds) { |
| 123 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); | 209 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); |
| 124 if (delegate.is_null()) | 210 if (delegate.is_null()) |
| 125 return; | 211 return; |
| 126 | 212 |
| 127 float scale = display::Screen::GetScreen() | 213 float dip_scale = GetDipScale(); |
| 128 ->GetDisplayNearestWindow(this) | 214 int left_margin = std::round(bounds.x() * dip_scale); |
| 129 .device_scale_factor(); | 215 int top_margin = std::round((content_offset().y() + bounds.y()) * dip_scale); |
| 130 int left_margin = std::round(bounds.x() * scale); | |
| 131 int top_margin = std::round((content_offset().y() + bounds.y()) * scale); | |
| 132 JNIEnv* env = base::android::AttachCurrentThread(); | 216 JNIEnv* env = base::android::AttachCurrentThread(); |
| 133 Java_ViewAndroidDelegate_setViewPosition( | 217 Java_ViewAndroidDelegate_setViewPosition( |
| 134 env, delegate, anchor, bounds.x(), bounds.y(), bounds.width(), | 218 env, delegate, anchor, bounds.x(), bounds.y(), bounds.width(), |
| 135 bounds.height(), scale, left_margin, top_margin); | 219 bounds.height(), dip_scale, left_margin, top_margin); |
| 136 } | 220 } |
| 137 | 221 |
| 138 ScopedJavaLocalRef<jobject> ViewAndroid::GetContainerView() { | 222 ScopedJavaLocalRef<jobject> ViewAndroid::GetContainerView() { |
| 139 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); | 223 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); |
| 140 if (delegate.is_null()) | 224 if (delegate.is_null()) |
| 141 return nullptr; | 225 return nullptr; |
| 142 | 226 |
| 143 JNIEnv* env = base::android::AttachCurrentThread(); | 227 JNIEnv* env = base::android::AttachCurrentThread(); |
| 144 return Java_ViewAndroidDelegate_getContainerView(env, delegate); | 228 return Java_ViewAndroidDelegate_getContainerView(env, delegate); |
| 145 } | 229 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 170 } | 254 } |
| 171 | 255 |
| 172 cc::Layer* ViewAndroid::GetLayer() const { | 256 cc::Layer* ViewAndroid::GetLayer() const { |
| 173 return layer_.get(); | 257 return layer_.get(); |
| 174 } | 258 } |
| 175 | 259 |
| 176 void ViewAndroid::SetLayer(scoped_refptr<cc::Layer> layer) { | 260 void ViewAndroid::SetLayer(scoped_refptr<cc::Layer> layer) { |
| 177 layer_ = layer; | 261 layer_ = layer; |
| 178 } | 262 } |
| 179 | 263 |
| 264 void ViewAndroid::SetLayout(int x, | |
| 265 int y, | |
| 266 int width, | |
| 267 int height, | |
| 268 bool match_parent) { | |
| 269 DCHECK(!match_parent || (x == 0 && y == 0 && width == 0 && height == 0)) | |
| 270 << "Should give empty dimension when view layout matches its parent. " | |
| 271 << "match_parent: " << match_parent << " x: " << x << " y: " << y | |
| 272 << " width: " << width << " height: " << height; | |
| 273 origin_.SetPoint(x, y); | |
| 274 size_.SetSize(width, height); | |
| 275 match_parent_ = match_parent; | |
| 276 } | |
| 277 | |
| 180 bool ViewAndroid::StartDragAndDrop(const JavaRef<jstring>& jtext, | 278 bool ViewAndroid::StartDragAndDrop(const JavaRef<jstring>& jtext, |
| 181 const JavaRef<jobject>& jimage) { | 279 const JavaRef<jobject>& jimage) { |
| 182 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); | 280 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); |
| 183 if (delegate.is_null()) | 281 if (delegate.is_null()) |
| 184 return false; | 282 return false; |
| 185 JNIEnv* env = base::android::AttachCurrentThread(); | 283 JNIEnv* env = base::android::AttachCurrentThread(); |
| 186 return Java_ViewAndroidDelegate_startDragAndDrop(env, delegate, jtext, | 284 return Java_ViewAndroidDelegate_startDragAndDrop(env, delegate, jtext, |
| 187 jimage); | 285 jimage); |
| 188 } | 286 } |
| 189 | 287 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 220 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); | 318 ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate()); |
| 221 if (delegate.is_null()) | 319 if (delegate.is_null()) |
| 222 return; | 320 return; |
| 223 JNIEnv* env = base::android::AttachCurrentThread(); | 321 JNIEnv* env = base::android::AttachCurrentThread(); |
| 224 ScopedJavaLocalRef<jstring> jcontent_url = | 322 ScopedJavaLocalRef<jstring> jcontent_url = |
| 225 ConvertUTF8ToJavaString(env, content_url.spec()); | 323 ConvertUTF8ToJavaString(env, content_url.spec()); |
| 226 Java_ViewAndroidDelegate_onStartContentIntent(env, delegate, jcontent_url, | 324 Java_ViewAndroidDelegate_onStartContentIntent(env, delegate, jcontent_url, |
| 227 is_main_frame); | 325 is_main_frame); |
| 228 } | 326 } |
| 229 | 327 |
| 328 bool ViewAndroid::OnTouchEvent(const MotionEventAndroid& event, | |
| 329 bool for_touch_handle) { | |
| 330 return HitTest(TouchEventSender(for_touch_handle), event); | |
| 331 } | |
| 332 | |
| 333 bool ViewAndroid::OnMouseEvent(const MotionEventAndroid& event) { | |
| 334 return HitTest(MouseEventSender(), event); | |
| 335 } | |
| 336 | |
| 337 bool ViewAndroid::HitTest(const EventSender& es, | |
|
boliu
2017/03/03 22:01:32
what you need here is argument binding, which of c
Jinsuk Kim
2017/03/06 04:07:34
Maybe I need your help on this. I tried Bind here
| |
| 338 const MotionEventAndroid& event) { | |
| 339 if (!children_.empty()) { | |
| 340 MotionEventAndroid e(event, -origin_.x(), -origin_.y()); | |
| 341 | |
| 342 // Match from back to front for hit testing. | |
| 343 for (auto* child : base::Reversed(children_)) { | |
| 344 bool matched = child->match_parent_; | |
| 345 if (!matched) { | |
| 346 gfx::Rect bound(child->origin_, child->size_); | |
| 347 matched = bound.Contains(e.GetX(0), e.GetY(0)); | |
| 348 } | |
| 349 if (matched && es.SendToView(child, e)) | |
|
Khushal
2017/03/03 23:36:08
Given that we first send the event to the children
Jinsuk Kim
2017/03/06 04:07:34
You're correct. See my other comment about switchi
| |
| 350 return true; | |
| 351 } | |
| 352 } | |
| 353 return client_ && es.SendToClient(client_, event); | |
| 354 } | |
| 355 | |
| 230 } // namespace ui | 356 } // namespace ui |
| OLD | NEW |