Loading startop/view_compiler/Android.bp +6 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ cc_defaults { "libdexfile", "slicer", ], static_libs: [ "libtinyxml2", ], } cc_library_host_static { Loading @@ -32,7 +35,9 @@ cc_library_host_static { srcs: [ "dex_builder.cc", "java_lang_builder.cc", "tinyxml_layout_parser.cc", "util.cc", "layout_validation.cc", ], } Loading @@ -43,7 +48,6 @@ cc_binary_host { "main.cc", ], static_libs: [ "libtinyxml2", "libgflags", "libviewcompiler", ], Loading @@ -54,6 +58,7 @@ cc_test_host { defaults: ["viewcompiler_defaults"], srcs: [ "dex_builder_test.cc", "layout_validation_test.cc", "util_test.cc", ], static_libs: [ Loading startop/view_compiler/layout_validation.cc 0 → 100644 +42 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "layout_validation.h" #include "android-base/stringprintf.h" namespace startop { void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) { if (0 == name.compare(u"merge")) { message_ = "Merge tags are not supported"; can_compile_ = false; } if (0 == name.compare(u"include")) { message_ = "Include tags are not supported"; can_compile_ = false; } if (0 == name.compare(u"view")) { message_ = "View tags are not supported"; can_compile_ = false; } if (0 == name.compare(u"fragment")) { message_ = "Fragment tags are not supported"; can_compile_ = false; } } } // namespace startop No newline at end of file startop/view_compiler/layout_validation.h 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LAYOUT_VALIDATION_H_ #define LAYOUT_VALIDATION_H_ #include "dex_builder.h" #include <string> namespace startop { // This visitor determines whether a layout can be compiled. Since we do not currently support all // features, such as includes and merges, we need to pre-validate the layout before we start // compiling. class LayoutValidationVisitor { public: void VisitStartDocument() const {} void VisitEndDocument() const {} void VisitStartTag(const std::u16string& name); void VisitEndTag() const {} const std::string& message() const { return message_; } bool can_compile() const { return can_compile_; } private: std::string message_{"Okay"}; bool can_compile_{true}; }; } // namespace startop #endif // LAYOUT_VALIDATION_H_ startop/view_compiler/layout_validation_test.cc 0 → 100644 +163 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "tinyxml_layout_parser.h" #include "gtest/gtest.h" using startop::CanCompileLayout; using std::string; namespace { void ValidateXmlText(const string& xml, bool expected) { tinyxml2::XMLDocument doc; doc.Parse(xml.c_str()); EXPECT_EQ(CanCompileLayout(doc), expected); } } // namespace TEST(LayoutValidationTest, SingleButtonLayout) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Hello, World!"> </Button>)"; ValidateXmlText(xml, /*expected=*/true); } TEST(LayoutValidationTest, SmallConstraintLayout) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginBottom="16dp" android:text="Button" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> <Button android:id="@+id/button7" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginBottom="16dp" android:text="Button2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/button6" /> <Button android:id="@+id/button8" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginBottom="16dp" android:text="Button1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/button7" /> </android.support.constraint.ConstraintLayout>)"; ValidateXmlText(xml, /*expected=*/true); } TEST(LayoutValidationTest, MergeNode) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> <Button android:id="@+id/button9" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" /> </merge>)"; ValidateXmlText(xml, /*expected=*/false); } TEST(LayoutValidationTest, IncludeLayout) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/single_button_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>)"; ValidateXmlText(xml, /*expected=*/false); } TEST(LayoutValidationTest, ViewNode) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <view class="android.support.design.button.MaterialButton" id="@+id/view" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>)"; ValidateXmlText(xml, /*expected=*/false); } TEST(LayoutValidationTest, FragmentNode) { // This test case is from https://developer.android.com/guide/components/fragments const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:name="com.example.news.ArticleListFragment" android:id="@+id/list" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.news.ArticleReaderFragment" android:id="@+id/viewer" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>)"; ValidateXmlText(xml, /*expected=*/false); } startop/view_compiler/main.cc +7 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "dex_builder.h" #include "java_lang_builder.h" #include "tinyxml_layout_parser.h" #include "util.h" #include "tinyxml2.h" Loading Loading @@ -100,6 +101,12 @@ int main(int argc, char** argv) { XMLDocument xml; xml.LoadFile(filename); string message{}; if (!startop::CanCompileLayout(xml, &message)) { LOG(ERROR) << "Layout not supported: " << message; return 1; } std::ofstream outfile; if (FLAGS_out != kStdoutFilename) { outfile.open(FLAGS_out); Loading Loading
startop/view_compiler/Android.bp +6 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ cc_defaults { "libdexfile", "slicer", ], static_libs: [ "libtinyxml2", ], } cc_library_host_static { Loading @@ -32,7 +35,9 @@ cc_library_host_static { srcs: [ "dex_builder.cc", "java_lang_builder.cc", "tinyxml_layout_parser.cc", "util.cc", "layout_validation.cc", ], } Loading @@ -43,7 +48,6 @@ cc_binary_host { "main.cc", ], static_libs: [ "libtinyxml2", "libgflags", "libviewcompiler", ], Loading @@ -54,6 +58,7 @@ cc_test_host { defaults: ["viewcompiler_defaults"], srcs: [ "dex_builder_test.cc", "layout_validation_test.cc", "util_test.cc", ], static_libs: [ Loading
startop/view_compiler/layout_validation.cc 0 → 100644 +42 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "layout_validation.h" #include "android-base/stringprintf.h" namespace startop { void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) { if (0 == name.compare(u"merge")) { message_ = "Merge tags are not supported"; can_compile_ = false; } if (0 == name.compare(u"include")) { message_ = "Include tags are not supported"; can_compile_ = false; } if (0 == name.compare(u"view")) { message_ = "View tags are not supported"; can_compile_ = false; } if (0 == name.compare(u"fragment")) { message_ = "Fragment tags are not supported"; can_compile_ = false; } } } // namespace startop No newline at end of file
startop/view_compiler/layout_validation.h 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LAYOUT_VALIDATION_H_ #define LAYOUT_VALIDATION_H_ #include "dex_builder.h" #include <string> namespace startop { // This visitor determines whether a layout can be compiled. Since we do not currently support all // features, such as includes and merges, we need to pre-validate the layout before we start // compiling. class LayoutValidationVisitor { public: void VisitStartDocument() const {} void VisitEndDocument() const {} void VisitStartTag(const std::u16string& name); void VisitEndTag() const {} const std::string& message() const { return message_; } bool can_compile() const { return can_compile_; } private: std::string message_{"Okay"}; bool can_compile_{true}; }; } // namespace startop #endif // LAYOUT_VALIDATION_H_
startop/view_compiler/layout_validation_test.cc 0 → 100644 +163 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "tinyxml_layout_parser.h" #include "gtest/gtest.h" using startop::CanCompileLayout; using std::string; namespace { void ValidateXmlText(const string& xml, bool expected) { tinyxml2::XMLDocument doc; doc.Parse(xml.c_str()); EXPECT_EQ(CanCompileLayout(doc), expected); } } // namespace TEST(LayoutValidationTest, SingleButtonLayout) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Hello, World!"> </Button>)"; ValidateXmlText(xml, /*expected=*/true); } TEST(LayoutValidationTest, SmallConstraintLayout) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginBottom="16dp" android:text="Button" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> <Button android:id="@+id/button7" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginBottom="16dp" android:text="Button2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/button6" /> <Button android:id="@+id/button8" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginBottom="16dp" android:text="Button1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/button7" /> </android.support.constraint.ConstraintLayout>)"; ValidateXmlText(xml, /*expected=*/true); } TEST(LayoutValidationTest, MergeNode) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> <Button android:id="@+id/button9" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" /> </merge>)"; ValidateXmlText(xml, /*expected=*/false); } TEST(LayoutValidationTest, IncludeLayout) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/single_button_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>)"; ValidateXmlText(xml, /*expected=*/false); } TEST(LayoutValidationTest, ViewNode) { const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <view class="android.support.design.button.MaterialButton" id="@+id/view" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>)"; ValidateXmlText(xml, /*expected=*/false); } TEST(LayoutValidationTest, FragmentNode) { // This test case is from https://developer.android.com/guide/components/fragments const string xml = R"(<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:name="com.example.news.ArticleListFragment" android:id="@+id/list" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.news.ArticleReaderFragment" android:id="@+id/viewer" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>)"; ValidateXmlText(xml, /*expected=*/false); }
startop/view_compiler/main.cc +7 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "dex_builder.h" #include "java_lang_builder.h" #include "tinyxml_layout_parser.h" #include "util.h" #include "tinyxml2.h" Loading Loading @@ -100,6 +101,12 @@ int main(int argc, char** argv) { XMLDocument xml; xml.LoadFile(filename); string message{}; if (!startop::CanCompileLayout(xml, &message)) { LOG(ERROR) << "Layout not supported: " << message; return 1; } std::ofstream outfile; if (FLAGS_out != kStdoutFilename) { outfile.open(FLAGS_out); Loading