Support non-disposed render in tests am: d84e1ead52 am: 2d583ba667 am: a92e3cff5c
Change-Id: I927c7dafc9f9a07b06d7b8259ea53a772d552e27
diff --git a/bridge/src/libcore/icu/ICU_Delegate.java b/bridge/src/libcore/icu/ICU_Delegate.java
index 880344f..708cf62 100644
--- a/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/bridge/src/libcore/icu/ICU_Delegate.java
@@ -75,72 +75,6 @@
}
@LayoutlibDelegate
- /*package*/ static boolean initLocaleDataNative(String locale, LocaleData result) {
-
- // Used by Calendar.
- result.firstDayOfWeek = 1;
- result.minimalDaysInFirstWeek = 1;
-
- // Used by DateFormatSymbols.
- result.amPm = new String[] { "AM", "PM" };
- result.eras = new String[] { "BC", "AD" };
-
- result.longMonthNames = new String[] { "January", "February", "March", "April", "May",
- "June", "July", "August", "September", "October", "November", "December" };
- result.shortMonthNames = new String[] { "Jan", "Feb", "Mar", "Apr", "May",
- "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
- result.longStandAloneMonthNames = result.longMonthNames;
- result.shortStandAloneMonthNames = result.shortMonthNames;
-
- // The platform code expects this to begin at index 1, rather than 0. It maps it directly to
- // the constants from java.util.Calendar.<weekday>
- result.longWeekdayNames = new String[] {
- "", "Sunday", "Monday" ,"Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
- result.shortWeekdayNames = new String[] {
- "", "Sun", "Mon" ,"Tue", "Wed", "Thu", "Fri", "Sat" };
- result.tinyWeekdayNames = new String[] {
- "", "S", "M", "T", "W", "T", "F", "S" };
-
- result.longStandAloneWeekdayNames = result.longWeekdayNames;
- result.shortStandAloneWeekdayNames = result.shortWeekdayNames;
- result.tinyStandAloneWeekdayNames = result.tinyWeekdayNames;
-
- result.fullTimeFormat = "";
- result.longTimeFormat = "";
- result.mediumTimeFormat = "";
- result.shortTimeFormat = "";
-
- result.fullDateFormat = "";
- result.longDateFormat = "";
- result.mediumDateFormat = "";
- result.shortDateFormat = "";
-
- // Used by DecimalFormatSymbols.
- result.zeroDigit = '0';
- result.decimalSeparator = '.';
- result.groupingSeparator = ',';
- result.patternSeparator = ' ';
- result.percent = "%";
- result.perMill = "\u2030";
- result.monetarySeparator = ' ';
- result.minusSign = "-";
- result.exponentSeparator = "e";
- result.infinity = "\u221E";
- result.NaN = "NaN";
- // Also used by Currency.
- result.currencySymbol = "$";
- result.internationalCurrencySymbol = "USD";
-
- // Used by DecimalFormat and NumberFormat.
- result.numberPattern = "%f";
- result.integerPattern = "%d";
- result.currencyPattern = "%s";
- result.percentPattern = "%f";
-
- return true;
- }
-
- @LayoutlibDelegate
/*package*/ static void setDefaultLocale(String locale) {
ICU.setDefaultLocale(locale);
}
diff --git a/bridge/tests/res/testApp/MyApplication/golden/a11y_test1.png b/bridge/tests/res/testApp/MyApplication/golden/a11y_test1.png
new file mode 100644
index 0000000..067a193
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/a11y_test1.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test1.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test1.xml
new file mode 100644
index 0000000..3af420c
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test1.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.widget.TextView
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:background="#000000"
+ android:gravity="center"
+ android:text="Hello!"
+ android:textColor="#000000" />
+
+
+ <Button
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:text="Hello World!!!"
+ />
+ <View
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:background="#000000"
+ android:importantForAccessibility="yes"
+ android:focusable="true"
+ android:clickable="true"
+ />
+</LinearLayout>
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 3db0644..9229d0d 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -22,6 +22,7 @@
import com.android.layoutlib.bridge.android.BridgeXmlBlockParserTest;
import com.android.layoutlib.bridge.impl.LayoutParserWrapperTest;
import com.android.layoutlib.bridge.impl.ResourceHelperTest;
+import com.android.tools.idea.validator.LayoutValidatorTests;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -44,7 +45,8 @@
Matrix_DelegateTest.class, TestDelegates.class,
BridgeRenderSessionTest.class, ResourceHelperTest.class, BridgeContextTest.class,
Resources_DelegateTest.class, Color_DelegateTest.class, ImagePoolHelperTest.class,
- ImagePoolImplTest.class, HighQualityShadowsRenderTests.class
+ ImagePoolImplTest.class, HighQualityShadowsRenderTests.class,
+ LayoutValidatorTests.class
})
public class Main {
}
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
index 6fbb955..b7f5bb0 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
@@ -63,6 +63,7 @@
private IImageFactory mImageFactory = null;
private boolean enableShadows = true;
private boolean highQualityShadows = true;
+ private boolean enableLayoutValidator = false;
@NonNull
public SessionParamsBuilder setParser(@NonNull LayoutPullParser layoutParser) {
@@ -176,6 +177,12 @@
}
@NonNull
+ public SessionParamsBuilder enableLayoutValidation() {
+ this.enableLayoutValidator = true;
+ return this;
+ }
+
+ @NonNull
public SessionParams build() {
assert mFrameworkResources != null;
assert mProjectResources != null;
@@ -198,6 +205,7 @@
mMinSdk, mTargetSdk, mLayoutLog);
params.setFlag(RenderParamsFlags.FLAG_ENABLE_SHADOW, enableShadows);
params.setFlag(RenderParamsFlags.FLAG_RENDER_HIGH_QUALITY_SHADOW, highQualityShadows);
+ params.setFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR, enableLayoutValidator);
if (mImageFactory != null) {
params.setImageFactory(mImageFactory);
}
diff --git a/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java
new file mode 100644
index 0000000..3de6bae
--- /dev/null
+++ b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.tools.idea.validator;
+
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.intensive.RenderTestBase;
+import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
+import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
+import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
+import com.android.tools.idea.validator.ValidatorData.Issue;
+import com.android.tools.idea.validator.ValidatorData.Level;
+import com.android.tools.idea.validator.ValidatorData.Type;
+
+import org.junit.Test;
+
+import android.view.View;
+
+import static org.junit.Assert.assertEquals;
+
+public class LayoutValidatorTests extends RenderTestBase {
+
+ @Test
+ public void testRenderAndVerify() throws Exception {
+ LayoutPullParser parser = createParserFromPath("a11y_test1.xml");
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+ layoutLibCallback.initResources();
+ SessionParams params = getSessionParamsBuilder()
+ .setParser(parser)
+ .setConfigGenerator(ConfigGenerator.NEXUS_5)
+ .setCallback(layoutLibCallback)
+ .disableDecoration()
+ .enableLayoutValidation()
+ .build();
+
+ renderAndVerify(params, "a11y_test1.png");
+ }
+
+ @Test
+ public void testValidation() throws Exception {
+ LayoutPullParser parser = createParserFromPath("a11y_test1.xml");
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+ layoutLibCallback.initResources();
+ SessionParams params = getSessionParamsBuilder()
+ .setParser(parser)
+ .setConfigGenerator(ConfigGenerator.NEXUS_5)
+ .setCallback(layoutLibCallback)
+ .disableDecoration()
+ .enableLayoutValidation()
+ .build();
+
+ render(sBridge, params, -1, session -> {
+ ValidatorResult result = LayoutValidator
+ .validate(((View) session.getRootViews().get(0).getViewObject()));
+ assertEquals(2, result.getIssues().size());
+ for (Issue issue : result.getIssues()) {
+ assertEquals(Type.ACCESSIBILITY, issue.mType);
+ assertEquals(Level.ERROR, issue.mLevel);
+ }
+
+ assertEquals("This item may not have a label readable by screen readers.",
+ result.getIssues().get(0).mMsg);
+ assertEquals(
+ "The item's text contrast ratio is 1.00. This ratio is based on a text color " +
+ "of #000000 and background color of #000000. Consider increasing this item's" +
+ " text contrast ratio to 3.00 or greater.",
+ result.getIssues().get(1).mMsg);
+ // TODO: It should recognize 10dp x 10dp button. Investigate why it's not.
+ });
+ }
+}
diff --git a/rename_font/build_font.py b/rename_font/build_font.py
index a53ebbc..db0c98a 100755
--- a/rename_font/build_font.py
+++ b/rename_font/build_font.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (C) 2014 The Android Open Source Project
#
@@ -96,7 +96,7 @@
def convert_font(input_path):
filename = os.path.basename(input_path)
- print 'Converting font: ' + filename
+ print('Converting font: ' + filename)
# the path to the output file. The file name is the fontfilename.ttx
ttx_path = os.path.join(dest_dir, filename)
ttx_path = ttx_path[:-1] + 'x'
@@ -116,11 +116,11 @@
ttx.main(ttx_args)
except InvalidFontException:
# In case of invalid fonts, we exit.
- print filename + ' is not a valid font'
+ print(filename + ' is not a valid font')
raise
except Exception as e:
- print 'Error converting font: ' + filename
- print e
+ print('Error converting font: ' + filename)
+ print(e)
# Some fonts are too big to be handled by the ttx library.
# Just copy paste them.
shutil.copy(input_path, dest_dir)
@@ -136,7 +136,7 @@
found in the name table of the font. """
fonts = []
font = None
- last_name_id = sys.maxint
+ last_name_id = sys.maxsize
for namerecord in tag.iter('namerecord'):
if 'nameID' in namerecord.attrib:
name_id = int(namerecord.attrib['nameID'])
@@ -164,14 +164,14 @@
def update_tag(tag, fonts):
- last_name_id = sys.maxint
+ last_name_id = sys.maxsize
fonts_iterator = fonts.__iter__()
font = None
for namerecord in tag.iter('namerecord'):
if 'nameID' in namerecord.attrib:
name_id = int(namerecord.attrib['nameID'])
if name_id <= last_name_id:
- font = fonts_iterator.next()
+ font = next(fonts_iterator)
font = update_font_name(font)
last_name_id = name_id
if name_id == NAMEID_FAMILY:
@@ -192,7 +192,7 @@
new_family = font.family + font.version
else:
new_family = font.family
- if font.style is 'Regular' and not font.ends_in_regular:
+ if font.style == 'Regular' and not font.ends_in_regular:
font.fullname = new_family
else:
font.fullname = new_family + ' ' + font.style
@@ -205,7 +205,7 @@
'Regular' for plain fonts. However, some fonts don't obey this rule. We
keep the style info, to minimize the diff. """
string = string.strip().split()[-1]
- return string is 'Regular'
+ return string == 'Regular'
def get_version(string):
diff --git a/rename_font/build_font_single.py b/rename_font/build_font_single.py
index 22d7fdf..b254072 100755
--- a/rename_font/build_font_single.py
+++ b/rename_font/build_font_single.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (C) 2014 The Android Open Source Project
#
@@ -71,7 +71,7 @@
def main(argv):
if len(argv) < 2:
- print 'Incorrect usage: ' + str(argv)
+ print('Incorrect usage: ' + str(argv))
sys.exit('Usage: build_font_single.py /path/to/input/font.ttf /path/to/out/font.ttf')
dest_path = argv[-1]
input_path = argv[0]
@@ -85,7 +85,7 @@
def convert_font(input_path, dest_path):
filename = os.path.basename(input_path)
- print 'Converting font: ' + filename
+ print('Converting font: ' + filename)
# the path to the output file. The file name is the fontfilename.ttx
ttx_path = dest_path[:-1] + 'x'
try:
@@ -104,11 +104,11 @@
ttx.main(ttx_args)
except InvalidFontException:
# assume, like for .ttc and .otf that font might be valid, but warn.
- print 'Family and/or Style nameIDs not found in '+ filename
+ print('Family and/or Style nameIDs not found in '+ filename)
shutil.copy(input_path, dest_path)
except Exception as e:
- print 'Error converting font: ' + filename
- print e
+ print('Error converting font: ' + filename)
+ print(e)
# Some fonts are too big to be handled by the ttx library.
# Just copy paste them.
shutil.copy(input_path, dest_path)
@@ -124,7 +124,7 @@
found in the name table of the font. """
fonts = []
font = None
- last_name_id = sys.maxint
+ last_name_id = sys.maxsize
for namerecord in tag.iter('namerecord'):
if 'nameID' in namerecord.attrib:
name_id = int(namerecord.attrib['nameID'])
@@ -155,7 +155,7 @@
def update_tag(tag, fonts):
- last_name_id = sys.maxint
+ last_name_id = sys.maxsize
fonts_iterator = fonts.__iter__()
font = None
for namerecord in tag.iter('namerecord'):
@@ -165,7 +165,7 @@
if name_id < NAMEID_LIST_MIN or name_id > NAMEID_LIST_MAX:
continue
if name_id <= last_name_id:
- font = fonts_iterator.next()
+ font = next(fonts_iterator)
font = update_font_name(font)
last_name_id = name_id
if name_id == NAMEID_FAMILY:
@@ -186,7 +186,7 @@
new_family = font.family + font.version
else:
new_family = font.family
- if font.style is 'Regular' and not font.ends_in_regular:
+ if font.style == 'Regular' and not font.ends_in_regular:
font.fullname = new_family
else:
font.fullname = new_family + ' ' + font.style
@@ -199,7 +199,7 @@
'Regular' for plain fonts. However, some fonts don't obey this rule. We
keep the style info, to minimize the diff. """
string = string.strip().split()[-1]
- return string is 'Regular'
+ return string == 'Regular'
def get_version(string):
diff --git a/rename_font/test.py b/rename_font/test.py
index 2ffddf4..cf26ee9 100755
--- a/rename_font/test.py
+++ b/rename_font/test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""Tests build_font.py by renaming a font.
@@ -22,10 +22,10 @@
def test(self):
font_name = "Roboto-Regular.ttf"
srcdir = tempfile.mkdtemp()
- print "srcdir: " + srcdir
+ print("srcdir: " + srcdir)
shutil.copy(font_name, srcdir)
destdir = tempfile.mkdtemp()
- print "destdir: " + destdir
+ print("destdir: " + destdir)
self.assertTrue(build_font.main([srcdir, destdir]) is None)
out_path = os.path.join(destdir, font_name)
ttx.main([out_path])