1 /* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef UI_MODEL_H 17 #define UI_MODEL_H 18 19 #include <vector> 20 #include <sstream> 21 #include "common_utilities_hpp.h" 22 #include "frontend_api_handler.h" 23 #include "json.hpp" 24 25 namespace OHOS::uitest { 26 using namespace std; 27 using namespace nlohmann; 28 const std::string ROOT_HIERARCHY = "ROOT"; 29 /**Enumerates the supported string value match rules.*/ 30 enum ValueMatchPattern : uint8_t { EQ, CONTAINS, STARTS_WITH, ENDS_WITH }; 31 32 /**Enumerates the supported UiComponent attributes.*/ 33 enum UiAttr : uint8_t { 34 ACCESSIBILITY_ID, 35 ID, 36 TEXT, 37 KEY, 38 DESCRIPTION, 39 TYPE, 40 BOUNDS, 41 ENABLED, 42 FOCUSED, 43 SELECTED, 44 CLICKABLE, 45 LONG_CLICKABLE, 46 SCROLLABLE, 47 CHECKABLE, 48 CHECKED, 49 HOST_WINDOW_ID, 50 ORIGBOUNDS, 51 // inner used attributes 52 HIERARCHY, 53 HASHCODE, 54 BOUNDSCENTER, 55 VISIBLE, 56 ABILITYNAME, 57 BUNDLENAME, 58 PAGEPATH, 59 DUMMY_ATTRNAME_SELECTION, 60 HINT, 61 MAX, // mark the max length 62 }; 63 64 /**Supported UiComponent attribute names. Ordered by <code>UiAttr</code> definition.*/ 65 constexpr std::string_view ATTR_NAMES[] = { 66 "accessibilityId", // ACCESSIBILITY_ID 67 "id", // ID 68 "text", // TEXT 69 "key", // KEY 70 "description", // DESCRIPTION 71 "type", // TYPE 72 "bounds", // BOUNDS 73 "enabled", // ENABLED 74 "focused", // FOCUSED 75 "selected", // SELECTED 76 "clickable", // CLICKABLE 77 "longClickable", // LONG_CLICKABLE 78 "scrollable", // SCROLLABLE 79 "checkable", // CHECKABLE 80 "checked", // CHECKED 81 "hostWindowId", // HOST_WINDOW_ID 82 "origBounds", // ORIGBOUNDS 83 "hierarchy", // HIERARCHY 84 "hashcode", // HASHCODE 85 "boundsCenter", // BOUNDSCENTER 86 "visible", // VISIBLE 87 "abilityName", // ABILITYNAME 88 "bundleName", // BUNDLENAME 89 "pagePath", // PAGEPATH 90 "dummyAttrnameSelection", // DUMMY_ATTRNAME_SELECTION 91 "hint", // HINT 92 }; 93 94 const std::set<std::string> CONTAINER_TYPE = { 95 "List", "Grid", "WaterFlow", "GridCol", "GridRow", "Scroll", "Flex", 96 "ListItemGroup", "Swiper", "DecorBar", "_Common_", "TabContent", "WindowScene"}; 97 struct Point { PointPoint98 Point() : px_(0), py_(0){}; PointPoint99 Point(int32_t px, int32_t py) : px_(px), py_(py){}; 100 int32_t px_; 101 int32_t py_; 102 }; 103 104 /**Represents a reasonable rectangle area.*/ 105 struct Rect { RectRect106 Rect(int32_t left, int32_t right, int32_t top, int32_t bottom) 107 : left_(left), right_(right), top_(top), bottom_(bottom) 108 { 109 DCHECK(right_ >= left_ && bottom_ >= top_); 110 }; RectRect111 Rect() 112 { 113 left_ = 0; 114 right_ = 0; 115 top_ = 0; 116 bottom_ = 0; 117 }; 118 int32_t left_; 119 int32_t right_; 120 int32_t top_; 121 int32_t bottom_; 122 GetCenterXRect123 FORCE_INLINE int32_t GetCenterX() const 124 { 125 return (left_ + right_) / TWO; 126 } 127 GetCenterYRect128 FORCE_INLINE int32_t GetCenterY() const 129 { 130 return (top_ + bottom_) / TWO; 131 } 132 GetWidthRect133 FORCE_INLINE int32_t GetWidth() const 134 { 135 return right_ - left_; 136 } 137 GetHeightRect138 FORCE_INLINE int32_t GetHeight() const 139 { 140 return bottom_ - top_; 141 } 142 DescribeRect143 std::string Describe() const 144 { 145 std::stringstream ss; 146 ss << "Rect {left:" << left_ << ",right:" << right_ << ",top:" << top_ << ",bottom:" << bottom_ << "}"; 147 return ss.str(); 148 } 149 }; 150 151 struct WidgetMatchModel { WidgetMatchModelWidgetMatchModel152 WidgetMatchModel(UiAttr name, string value, ValueMatchPattern matchPattern) 153 : attrName(name), attrValue(value), pattern(matchPattern) 154 { 155 } WidgetMatchModelWidgetMatchModel156 WidgetMatchModel() {} DescribeWidgetMatchModel157 std::string Describe() const 158 { 159 stringstream ss; 160 ss << "{"; 161 ss << "attrName:" << ATTR_NAMES[attrName].data() << "; value:" << attrValue 162 << "; Pattern:" << to_string(pattern); 163 ss << "}"; 164 return ss.str(); 165 } 166 UiAttr attrName; 167 string attrValue; 168 ValueMatchPattern pattern; 169 }; 170 171 /**Algorithm of rectangle.*/ 172 class RectAlgorithm { 173 public: 174 FORCE_INLINE static bool CheckEqual(const Rect &ra, const Rect &rb); 175 FORCE_INLINE static bool CheckIntersectant(const Rect &ra, const Rect &rb); 176 FORCE_INLINE static bool IsInnerPoint(const Rect &rect, const Point &point); 177 FORCE_INLINE static bool IsPointOnEdge(const Rect &rect, const Point &point); 178 static bool ComputeIntersection(const Rect &ra, const Rect &rb, Rect &result); 179 static bool ComputeMaxVisibleRegion(const Rect &rect, const std::vector<Rect> &overlays, Rect &out); 180 }; 181 CheckEqual(const Rect & ra,const Rect & rb)182 FORCE_INLINE bool RectAlgorithm::CheckEqual(const Rect &ra, const Rect &rb) 183 { 184 return ra.left_ == rb.left_ && ra.right_ == rb.right_ && ra.top_ == rb.top_ && ra.bottom_ == rb.bottom_; 185 } 186 CheckIntersectant(const Rect & ra,const Rect & rb)187 FORCE_INLINE bool RectAlgorithm::CheckIntersectant(const Rect &ra, const Rect &rb) 188 { 189 if (ra.left_ >= rb.right_ || ra.right_ <= rb.left_) { 190 return false; 191 } 192 if (ra.top_ >= rb.bottom_ || ra.bottom_ <= rb.top_) { 193 return false; 194 } 195 return true; 196 } 197 IsInnerPoint(const Rect & rect,const Point & point)198 FORCE_INLINE bool RectAlgorithm::IsInnerPoint(const Rect &rect, const Point& point) 199 { 200 if (point.px_ <= rect.left_ || point.px_ >= rect.right_ 201 || point.py_ <= rect.top_ || point.py_ >= rect.bottom_) { 202 return false; 203 } 204 return true; 205 } 206 IsPointOnEdge(const Rect & rect,const Point & point)207 FORCE_INLINE bool RectAlgorithm::IsPointOnEdge(const Rect &rect, const Point& point) 208 { 209 if ((point.px_ == rect.left_ || point.px_ == rect.right_) 210 && point.py_ >= rect.top_ && point.py_ <= rect.bottom_) { 211 return true; 212 } 213 if ((point.py_ == rect.top_ || point.py_ == rect.bottom_) 214 && point.px_ >= rect.left_ && point.px_ <= rect.right_) { 215 return true; 216 } 217 return false; 218 } 219 220 class Widget : public BackendClass { 221 public: 222 // disable default constructor, copy constructor and assignment operator Widget(std::string_view hierarchy)223 explicit Widget(std::string_view hierarchy) : hierarchy_(hierarchy) 224 { 225 attributeVec_[UiAttr::HIERARCHY] = hierarchy; 226 }; 227 ~Widget()228 ~Widget() override {} 229 GetFrontendClassDef()230 const FrontEndClassDef &GetFrontendClassDef() const override 231 { 232 return COMPONENT_DEF; 233 } 234 GetBounds()235 Rect GetBounds() const 236 { 237 return bounds_; 238 } 239 GetHierarchy()240 std::string GetHierarchy() const 241 { 242 return hierarchy_; 243 } 244 245 void SetBounds(const Rect &bounds); 246 247 std::string ToStr() const; 248 249 std::unique_ptr<Widget> Clone(std::string_view hierarchy) const; 250 251 std::vector<std::string> GetAttrVec() const; 252 IsVisible()253 bool IsVisible() const 254 { 255 return GetAttr(UiAttr::VISIBLE) == "true"; 256 } 257 258 void SetAttr(UiAttr attrId, string value); 259 260 std::string GetAttr(UiAttr attrId) const; 261 262 bool MatchAttr(const WidgetMatchModel& matchModel) const; 263 264 void SetHierarchy(const std::string& hierarch); 265 266 void WrapperWidgetToJson(nlohmann::json& out); 267 private: 268 std::string hierarchy_; 269 std::vector<string> attributeVec_ = std::vector<string>(UiAttr::MAX + 1); 270 Rect bounds_ = {0, 0, 0, 0}; 271 }; 272 273 // ensure Widget is movable, since we need to move a constructed Widget object into WidgetTree 274 static_assert(std::is_move_constructible<Widget>::value, "Widget need to be movable"); 275 276 /**Enumerates the supported UiComponent attributes.*/ 277 enum WindowMode : uint8_t { UNKNOWN, FULLSCREEN, SPLIT_PRIMARY, SPLIT_SECONDARY, FLOATING, PIP }; 278 279 // Represents a UI window on screen. 280 class Window : public BackendClass { 281 public: Window(int32_t id)282 explicit Window(int32_t id) : id_(id) {}; 283 ~Window()284 ~Window() override {} 285 GetFrontendClassDef()286 const FrontEndClassDef &GetFrontendClassDef() const override 287 { 288 return UI_WINDOW_DEF; 289 } 290 291 // plain properties, make them public for easy access 292 int32_t id_ = 0; 293 int32_t windowLayer_ = 0; 294 std::string bundleName_ = ""; 295 std::string title_ = ""; 296 bool focused_ = false; 297 bool actived_ = false; 298 bool decoratorEnabled_ = false; 299 Rect bounds_ = {0, 0, 0, 0}; 300 Rect visibleBounds_ = {0, 0, 0, 0}; 301 std::vector<Rect> invisibleBoundsVec_; 302 std::string abilityName_ = ""; 303 std::string pagePath_ = ""; 304 WindowMode mode_ = UNKNOWN; 305 }; 306 307 class DumpHandler { 308 public: 309 static void AddExtraAttrs(nlohmann::json &root, const map<int32_t, string_view> &elementTrees, size_t index); 310 static void DumpWindowInfoToJson(vector<Widget> &allWidget, nlohmann::json &root); 311 }; 312 313 class WidgetHierarchyBuilder { 314 public: 315 static string Build(string_view parentWidgetHierarchy, uint32_t childIndex); 316 317 static string GetParentWidgetHierarchy(string_view hierarchy); 318 319 static string GetChildHierarchy(string_view hierarchy, uint32_t childIndex); 320 321 private: 322 static constexpr auto HIERARCHY_SEPARATOR = ","; 323 }; 324 } // namespace OHOS::uitest 325 326 #endif