summaryrefslogtreecommitdiff
path: root/library/gingerbread
diff options
context:
space:
mode:
authorMaurice Lam <yukl@google.com>2017-03-28 12:48:40 -0700
committerMaurice Lam <yukl@google.com>2017-03-28 14:23:21 -0700
commit83862bb59558fc044de9aa0d6e9407be53af8b81 (patch)
tree032855cc188420699c048478a6a24c44731a3151 /library/gingerbread
parent9955331ed7bda114488b1a4701456ec478ff63bf (diff)
downloadsetupwizard-83862bb59558fc044de9aa0d6e9407be53af8b81.tar.gz
Rename SuwLib directories
Rename eclair-mr1 to gingerbread to reflect the min SDK version change, and full-support to recyclerview to better reflect what's inside the directory Also added comments and applied style fixes to keep checkstyle happy. Test: Existing tests pass Change-Id: I20332f718f2aae04092d5e45de944b1efce1a596
Diffstat (limited to 'library/gingerbread')
-rw-r--r--library/gingerbread/res/drawable-hdpi/suw_navbar_ic_down_arrow.pngbin0 -> 160 bytes
-rw-r--r--library/gingerbread/res/drawable-hdpi/suw_navbar_ic_left_arrow.pngbin0 -> 132 bytes
-rw-r--r--library/gingerbread/res/drawable-hdpi/suw_navbar_ic_right_arrow.pngbin0 -> 133 bytes
-rw-r--r--library/gingerbread/res/drawable-ldrtl/suw_navbar_ic_back.xml19
-rw-r--r--library/gingerbread/res/drawable-ldrtl/suw_navbar_ic_next.xml19
-rw-r--r--library/gingerbread/res/drawable-mdpi/suw_navbar_ic_down_arrow.pngbin0 -> 140 bytes
-rw-r--r--library/gingerbread/res/drawable-mdpi/suw_navbar_ic_left_arrow.pngbin0 -> 114 bytes
-rw-r--r--library/gingerbread/res/drawable-mdpi/suw_navbar_ic_right_arrow.pngbin0 -> 108 bytes
-rw-r--r--library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.pngbin0 -> 191 bytes
-rw-r--r--library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_left_arrow.pngbin0 -> 137 bytes
-rw-r--r--library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_right_arrow.pngbin0 -> 140 bytes
-rw-r--r--library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.pngbin0 -> 257 bytes
-rw-r--r--library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.pngbin0 -> 192 bytes
-rw-r--r--library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.pngbin0 -> 208 bytes
-rw-r--r--library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.pngbin0 -> 280 bytes
-rw-r--r--library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_left_arrow.pngbin0 -> 194 bytes
-rw-r--r--library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_right_arrow.pngbin0 -> 207 bytes
-rw-r--r--library/gingerbread/res/drawable/suw_card_bg_dark.xml28
-rw-r--r--library/gingerbread/res/drawable/suw_card_bg_light.xml28
-rw-r--r--library/gingerbread/res/drawable/suw_ic_expand.xml21
-rw-r--r--library/gingerbread/res/drawable/suw_ic_expand_less.xml26
-rw-r--r--library/gingerbread/res/drawable/suw_ic_expand_more.xml26
-rw-r--r--library/gingerbread/res/drawable/suw_navbar_btn_bg_dark.xml30
-rw-r--r--library/gingerbread/res/drawable/suw_navbar_btn_bg_light.xml31
-rw-r--r--library/gingerbread/res/drawable/suw_navbar_ic_back.xml19
-rw-r--r--library/gingerbread/res/drawable/suw_navbar_ic_more.xml19
-rw-r--r--library/gingerbread/res/drawable/suw_navbar_ic_next.xml19
-rw-r--r--library/gingerbread/res/layout/suw_items_expandable_switch.xml107
-rw-r--r--library/gingerbread/res/layout/suw_items_switch.xml77
-rw-r--r--library/gingerbread/res/layout/suw_progress_bar.xml25
-rw-r--r--library/gingerbread/res/values/attrs.xml29
-rw-r--r--library/gingerbread/res/values/dimens.xml29
-rw-r--r--library/gingerbread/res/values/styles.xml238
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java172
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/items/SwitchItem.java133
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java236
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/view/NavigationBarButton.java159
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java167
-rw-r--r--library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/items/ButtonItemDrawingTest.java85
-rw-r--r--library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/LinkAccessibilityHelperTest.java294
-rw-r--r--library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/RichTextViewTest.java127
-rw-r--r--library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java30
-rw-r--r--library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/ExpandableSwitchItemTest.java189
-rw-r--r--library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java231
44 files changed, 2613 insertions, 0 deletions
diff --git a/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_down_arrow.png b/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_down_arrow.png
new file mode 100644
index 0000000..3d7f83f
--- /dev/null
+++ b/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_left_arrow.png b/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_left_arrow.png
new file mode 100644
index 0000000..decccac
--- /dev/null
+++ b/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_left_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_right_arrow.png b/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_right_arrow.png
new file mode 100644
index 0000000..5ba56b7
--- /dev/null
+++ b/library/gingerbread/res/drawable-hdpi/suw_navbar_ic_right_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-ldrtl/suw_navbar_ic_back.xml b/library/gingerbread/res/drawable-ldrtl/suw_navbar_ic_back.xml
new file mode 100644
index 0000000..e164e8a
--- /dev/null
+++ b/library/gingerbread/res/drawable-ldrtl/suw_navbar_ic_back.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/suw_navbar_ic_right_arrow" />
diff --git a/library/gingerbread/res/drawable-ldrtl/suw_navbar_ic_next.xml b/library/gingerbread/res/drawable-ldrtl/suw_navbar_ic_next.xml
new file mode 100644
index 0000000..8a6e137
--- /dev/null
+++ b/library/gingerbread/res/drawable-ldrtl/suw_navbar_ic_next.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/suw_navbar_ic_left_arrow" />
diff --git a/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_down_arrow.png b/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_down_arrow.png
new file mode 100644
index 0000000..5b1fa06
--- /dev/null
+++ b/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_left_arrow.png b/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_left_arrow.png
new file mode 100644
index 0000000..1e2984a
--- /dev/null
+++ b/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_left_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_right_arrow.png b/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_right_arrow.png
new file mode 100644
index 0000000..b8365e6
--- /dev/null
+++ b/library/gingerbread/res/drawable-mdpi/suw_navbar_ic_right_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.png b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.png
new file mode 100644
index 0000000..94016f4
--- /dev/null
+++ b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_left_arrow.png b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_left_arrow.png
new file mode 100644
index 0000000..2d2046c
--- /dev/null
+++ b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_left_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_right_arrow.png b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_right_arrow.png
new file mode 100644
index 0000000..46abe31
--- /dev/null
+++ b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_right_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.png b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.png
new file mode 100644
index 0000000..17811ae
--- /dev/null
+++ b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.png b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.png
new file mode 100644
index 0000000..97fed92
--- /dev/null
+++ b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.png b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.png
new file mode 100644
index 0000000..f874955
--- /dev/null
+++ b/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png
new file mode 100644
index 0000000..cb6a422
--- /dev/null
+++ b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_left_arrow.png b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_left_arrow.png
new file mode 100644
index 0000000..a0ebbb9
--- /dev/null
+++ b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_left_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_right_arrow.png b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_right_arrow.png
new file mode 100644
index 0000000..c98b882
--- /dev/null
+++ b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_right_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/drawable/suw_card_bg_dark.xml b/library/gingerbread/res/drawable/suw_card_bg_dark.xml
new file mode 100644
index 0000000..cd115cf
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_card_bg_dark.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:shape="rectangle">
+
+ <corners
+ android:topLeftRadius="@dimen/suw_card_corner_radius"
+ android:topRightRadius="@dimen/suw_card_corner_radius" />
+
+ <!-- Ignore PrivateResource: This should be fixed -->
+ <solid android:color="@color/background_material_dark" tools:ignore="PrivateResource" />
+
+</shape>
diff --git a/library/gingerbread/res/drawable/suw_card_bg_light.xml b/library/gingerbread/res/drawable/suw_card_bg_light.xml
new file mode 100644
index 0000000..cd40dbe
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_card_bg_light.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:shape="rectangle">
+
+ <corners
+ android:topLeftRadius="@dimen/suw_card_corner_radius"
+ android:topRightRadius="@dimen/suw_card_corner_radius" />
+
+ <!-- Ignore PrivateResource: This should be fixed -->
+ <solid android:color="@color/background_material_light" tools:ignore="PrivateResource" />
+
+</shape>
diff --git a/library/gingerbread/res/drawable/suw_ic_expand.xml b/library/gingerbread/res/drawable/suw_ic_expand.xml
new file mode 100644
index 0000000..7e79f7d
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_ic_expand.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true" android:drawable="@drawable/suw_ic_expand_less" />
+ <item android:drawable="@drawable/suw_ic_expand_more" />
+</selector>
diff --git a/library/gingerbread/res/drawable/suw_ic_expand_less.xml b/library/gingerbread/res/drawable/suw_ic_expand_less.xml
new file mode 100644
index 0000000..e639a61
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_ic_expand_less.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="18dp"
+ android:height="18dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path
+ android:fillColor="#ff000000"
+ android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z" />
+</vector>
diff --git a/library/gingerbread/res/drawable/suw_ic_expand_more.xml b/library/gingerbread/res/drawable/suw_ic_expand_more.xml
new file mode 100644
index 0000000..ed63e21
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_ic_expand_more.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="18dp"
+ android:height="18dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#ff000000"
+ android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
+</vector>
diff --git a/library/gingerbread/res/drawable/suw_navbar_btn_bg_dark.xml b/library/gingerbread/res/drawable/suw_navbar_btn_bg_dark.xml
new file mode 100644
index 0000000..f4131e5
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_navbar_btn_bg_dark.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <item android:state_pressed="true">
+ <!-- Ignore PrivateResource: This should be fixed -->
+ <color android:color="@color/ripple_material_dark" tools:ignore="PrivateResource" />
+ </item>
+
+ <item>
+ <color android:color="@android:color/transparent" />
+ </item>
+
+</selector>
diff --git a/library/gingerbread/res/drawable/suw_navbar_btn_bg_light.xml b/library/gingerbread/res/drawable/suw_navbar_btn_bg_light.xml
new file mode 100644
index 0000000..5d3bcfa
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_navbar_btn_bg_light.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<selector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <item android:state_pressed="true">
+ <!-- Ignore PrivateResource: This should be fixed -->
+ <color android:color="@color/ripple_material_light" tools:ignore="PrivateResource" />
+ </item>
+
+ <item>
+ <color android:color="@android:color/transparent" />
+ </item>
+
+</selector>
diff --git a/library/gingerbread/res/drawable/suw_navbar_ic_back.xml b/library/gingerbread/res/drawable/suw_navbar_ic_back.xml
new file mode 100644
index 0000000..8a6e137
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_navbar_ic_back.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/suw_navbar_ic_left_arrow" />
diff --git a/library/gingerbread/res/drawable/suw_navbar_ic_more.xml b/library/gingerbread/res/drawable/suw_navbar_ic_more.xml
new file mode 100644
index 0000000..603e08d
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_navbar_ic_more.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/suw_navbar_ic_down_arrow" />
diff --git a/library/gingerbread/res/drawable/suw_navbar_ic_next.xml b/library/gingerbread/res/drawable/suw_navbar_ic_next.xml
new file mode 100644
index 0000000..e164e8a
--- /dev/null
+++ b/library/gingerbread/res/drawable/suw_navbar_ic_next.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/suw_navbar_ic_right_arrow" />
diff --git a/library/gingerbread/res/layout/suw_items_expandable_switch.xml b/library/gingerbread/res/layout/suw_items_expandable_switch.xml
new file mode 100644
index 0000000..91e482d
--- /dev/null
+++ b/library/gingerbread/res/layout/suw_items_expandable_switch.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2017 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:colorBackground"
+ android:descendantFocusability="blocksDescendants"
+ android:orientation="horizontal"
+ android:tag="noBackground">
+
+ <com.android.setupwizardlib.view.CheckableLinearLayout
+ android:id="@+id/suw_items_expandable_switch_content"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ style="@style/SuwItemContainer"
+ android:layout_weight="1"
+ android:background="?attr/selectableItemBackground"
+ android:baselineAligned="false"
+ android:orientation="horizontal"
+ android:paddingEnd="@dimen/suw_switch_content_padding_end"
+ android:paddingLeft="?attr/listPreferredItemPaddingLeft"
+ android:paddingRight="@dimen/suw_switch_content_padding_end"
+ android:paddingStart="?attr/listPreferredItemPaddingLeft">
+
+ <FrameLayout
+ android:id="@+id/suw_items_icon_container"
+ android:layout_width="@dimen/suw_items_icon_container_width"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:gravity="start">
+
+ <ImageView
+ android:id="@+id/suw_items_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ tools:ignore="ContentDescription" />
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/suw_items_padding_bottom_extra"
+ android:layout_weight="1"
+ android:duplicateParentState="true"
+ android:orientation="vertical">
+
+ <com.android.setupwizardlib.view.RichTextView
+ android:id="@+id/suw_items_title"
+ style="@style/SuwItemTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawablePadding="@dimen/suw_expand_arrow_drawable_padding"
+ android:drawableEnd="@drawable/suw_ic_expand"
+ android:drawableRight="@drawable/suw_ic_expand"
+ android:duplicateParentState="true"
+ android:gravity="start"
+ android:labelFor="@+id/suw_items_switch"
+ android:textAlignment="viewStart"
+ tools:ignore="UnusedAttribute" />
+
+ <com.android.setupwizardlib.view.RichTextView
+ android:id="@+id/suw_items_summary"
+ style="@style/SuwItemSummary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:duplicateParentState="true"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:visibility="gone"
+ tools:ignore="UnusedAttribute" />
+
+ </LinearLayout>
+
+ </com.android.setupwizardlib.view.CheckableLinearLayout>
+
+ <View
+ android:id="@+id/suw_items_switch_divider"
+ android:layout_width="1dp"
+ android:layout_height="@dimen/suw_switch_divider_height"
+ android:layout_gravity="center_vertical"
+ android:background="?android:attr/listDivider" />
+
+ <android.support.v7.widget.SwitchCompat
+ android:id="@+id/suw_items_switch"
+ style="@style/SuwSwitchStyle.Divided"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical" />
+
+</LinearLayout>
diff --git a/library/gingerbread/res/layout/suw_items_switch.xml b/library/gingerbread/res/layout/suw_items_switch.xml
new file mode 100644
index 0000000..af326b2
--- /dev/null
+++ b/library/gingerbread/res/layout/suw_items_switch.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2016 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ style="@style/SuwItemContainer.Verbose"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:descendantFocusability="blocksDescendants"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:id="@+id/suw_items_icon_container"
+ android:layout_width="@dimen/suw_items_icon_container_width"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:gravity="start">
+
+ <ImageView
+ android:id="@+id/suw_items_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ tools:ignore="ContentDescription" />
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/suw_items_verbose_padding_bottom_extra"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <com.android.setupwizardlib.view.RichTextView
+ android:id="@+id/suw_items_title"
+ style="@style/SuwItemTitle.Verbose"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:labelFor="@+id/suw_items_switch"
+ android:textAlignment="viewStart"
+ tools:ignore="UnusedAttribute" />
+
+ <com.android.setupwizardlib.view.RichTextView
+ android:id="@+id/suw_items_summary"
+ style="@style/SuwItemSummary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:textAlignment="viewStart"
+ android:visibility="gone"
+ tools:ignore="UnusedAttribute" />
+
+ </LinearLayout>
+
+ <android.support.v7.widget.SwitchCompat
+ android:id="@+id/suw_items_switch"
+ style="@style/SuwSwitchStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical" />
+
+</LinearLayout>
diff --git a/library/gingerbread/res/layout/suw_progress_bar.xml b/library/gingerbread/res/layout/suw_progress_bar.xml
new file mode 100644
index 0000000..35e0faf
--- /dev/null
+++ b/library/gingerbread/res/layout/suw_progress_bar.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/progress_bar"
+ style="@style/Widget.AppCompat.ProgressBar.Horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/suw_progress_bar_margin_vertical"
+ android:layout_marginTop="@dimen/suw_progress_bar_margin_vertical"
+ android:indeterminate="true" />
diff --git a/library/gingerbread/res/values/attrs.xml b/library/gingerbread/res/values/attrs.xml
new file mode 100644
index 0000000..2a7b5cd
--- /dev/null
+++ b/library/gingerbread/res/values/attrs.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2016 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.
+-->
+
+<resources>
+
+ <declare-styleable name="SuwSwitchItem">
+ <attr name="android:checked" />
+ </declare-styleable>
+
+ <declare-styleable name="SuwExpandableSwitchItem">
+ <attr name="suwCollapsedSummary" format="string" localization="suggested" />
+ <attr name="suwExpandedSummary" format="string" localization="suggested" />
+ </declare-styleable>
+
+</resources>
diff --git a/library/gingerbread/res/values/dimens.xml b/library/gingerbread/res/values/dimens.xml
new file mode 100644
index 0000000..d40d7de
--- /dev/null
+++ b/library/gingerbread/res/values/dimens.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2017 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.
+-->
+
+<resources>
+
+ <!-- SwitchItem -->
+ <dimen name="suw_switch_padding_start">16dp</dimen>
+ <dimen name="suw_switch_padding_end">0dp</dimen>
+ <dimen name="suw_switch_divider_height">32dp</dimen>
+ <dimen name="suw_switch_content_padding_end">16dp</dimen>
+
+ <!-- ExpandableSwithItem -->
+ <dimen name="suw_expand_arrow_drawable_padding">6dp</dimen>
+
+</resources>
diff --git a/library/gingerbread/res/values/styles.xml b/library/gingerbread/res/values/styles.xml
new file mode 100644
index 0000000..1ea468d
--- /dev/null
+++ b/library/gingerbread/res/values/styles.xml
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+
+ <!-- General styles -->
+
+ <style name="SuwThemeMaterial" parent="Theme.AppCompat.NoActionBar">
+ <item name="android:indeterminateTint" tools:ignore="NewApi">@color/suw_progress_bar_color_dark</item>
+ <!-- Specify the indeterminateTintMode to work around a bug in Lollipop -->
+ <item name="android:indeterminateTintMode" tools:ignore="NewApi">src_in</item>
+ <item name="android:listPreferredItemHeight">@dimen/suw_items_preferred_height</item>
+ <item name="android:navigationBarColor" tools:ignore="NewApi">@android:color/black</item>
+ <item name="android:statusBarColor" tools:ignore="NewApi">@android:color/black</item>
+ <item name="android:textAppearanceListItemSmall" tools:ignore="NewApi">?attr/textAppearanceListItemSmall</item>
+ <item name="android:textColorLink">@color/suw_link_color_dark</item>
+ <item name="android:windowAnimationStyle">@style/Animation.SuwWindowAnimation</item>
+ <item name="android:windowDisablePreview">true</item>
+ <item name="android:windowSoftInputMode">adjustResize</item>
+
+ <item name="colorAccent">@color/suw_color_accent_dark</item>
+ <item name="listPreferredItemPaddingLeft">?attr/suwMarginSides</item>
+ <item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
+ <item name="suwCardBackground">@drawable/suw_card_bg_dark</item>
+ <item name="suwItemDescriptionStyle">@style/SuwItemContainer.Description</item>
+ <item name="suwListItemIconColor">@color/suw_list_item_icon_color_dark</item>
+ <item name="suwMarginSides">@dimen/suw_layout_margin_sides</item>
+ <item name="suwNavBarTheme">@style/SuwNavBarThemeDark</item>
+ <item name="textAppearanceListItemSmall">@style/TextAppearance.SuwItemSummary</item>
+ </style>
+
+ <style name="SuwThemeMaterial.Light" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="android:indeterminateTint" tools:ignore="NewApi">@color/suw_progress_bar_color_light</item>
+ <!-- Specify the indeterminateTintMode to work around a bug in Lollipop -->
+ <item name="android:indeterminateTintMode" tools:ignore="NewApi">src_in</item>
+ <item name="android:listPreferredItemHeight">@dimen/suw_items_preferred_height</item>
+ <item name="android:navigationBarColor" tools:ignore="NewApi">@android:color/black</item>
+ <item name="android:statusBarColor" tools:ignore="NewApi">@android:color/black</item>
+ <item name="android:textAppearanceListItemSmall" tools:ignore="NewApi">?attr/textAppearanceListItemSmall</item>
+ <item name="android:textColorLink">@color/suw_link_color_light</item>
+ <item name="android:windowAnimationStyle">@style/Animation.SuwWindowAnimation</item>
+ <item name="android:windowDisablePreview">true</item>
+ <item name="android:windowSoftInputMode">adjustResize</item>
+
+ <item name="colorAccent">@color/suw_color_accent_light</item>
+ <item name="listPreferredItemPaddingLeft">?attr/suwMarginSides</item>
+ <item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
+ <item name="suwCardBackground">@drawable/suw_card_bg_light</item>
+ <item name="suwItemDescriptionStyle">@style/SuwItemContainer.Description</item>
+ <item name="suwListItemIconColor">@color/suw_list_item_icon_color_light</item>
+ <item name="suwMarginSides">@dimen/suw_layout_margin_sides</item>
+ <item name="suwNavBarTheme">@style/SuwNavBarThemeLight</item>
+ <item name="textAppearanceListItemSmall">@style/TextAppearance.SuwItemSummary</item>
+ </style>
+
+ <style name="SuwThemeGlif" parent="Theme.AppCompat.NoActionBar">
+ <item name="android:indeterminateTint" tools:ignore="NewApi">?attr/colorControlActivated</item>
+ <!-- Specify the indeterminateTintMode to work around a bug in Lollipop -->
+ <item name="android:indeterminateTintMode" tools:ignore="NewApi">src_in</item>
+ <item name="android:listPreferredItemHeight">@dimen/suw_items_preferred_height</item>
+ <item name="android:listPreferredItemPaddingEnd" tools:ignore="NewApi">?attr/suwMarginSides</item>
+ <item name="android:listPreferredItemPaddingStart" tools:ignore="NewApi">?attr/suwMarginSides</item>
+ <item name="android:navigationBarColor" tools:ignore="NewApi">@android:color/black</item>
+ <item name="android:statusBarColor" tools:ignore="NewApi">@android:color/transparent</item>
+ <item name="android:textAppearanceListItemSmall" tools:ignore="NewApi">?attr/textAppearanceListItemSmall</item>
+ <item name="android:textColorLink">@color/suw_link_color_dark</item>
+ <item name="android:windowAnimationStyle">@style/Animation.SuwWindowAnimation</item>
+ <item name="android:windowDisablePreview">true</item>
+ <item name="android:windowSoftInputMode">adjustResize</item>
+
+ <item name="colorAccent">@color/suw_color_accent_glif_dark</item>
+ <item name="colorPrimary">@color/suw_color_accent_glif_dark</item>
+ <item name="listPreferredItemPaddingLeft">?attr/suwMarginSides</item>
+ <item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
+ <item name="suwColorPrimary">?attr/colorPrimary</item>
+ <item name="suwDividerInset">@dimen/suw_items_glif_icon_divider_inset</item>
+ <item name="suwGlifHeaderGravity">start</item>
+ <item name="suwItemDescriptionStyle">@style/SuwItemContainer.Description.Glif</item>
+ <item name="suwListItemIconColor">@color/suw_list_item_icon_color_dark</item>
+ <item name="suwMarginSides">@dimen/suw_glif_margin_sides</item>
+ <item name="suwScrollIndicators">bottom</item>
+ <item name="textAppearanceListItem">@style/TextAppearance.SuwGlifItemTitle</item>
+ <item name="textAppearanceListItemSmall">@style/TextAppearance.SuwGlifItemSummary</item>
+ </style>
+
+ <style name="SuwThemeGlif.Light" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="android:indeterminateTint" tools:ignore="NewApi">?attr/colorControlActivated</item>
+ <!-- Specify the indeterminateTintMode to work around a bug in Lollipop -->
+ <item name="android:indeterminateTintMode" tools:ignore="NewApi">src_in</item>
+ <item name="android:listPreferredItemHeight">@dimen/suw_items_preferred_height</item>
+ <item name="android:listPreferredItemPaddingEnd" tools:ignore="NewApi">?attr/suwMarginSides</item>
+ <item name="android:listPreferredItemPaddingStart" tools:ignore="NewApi">?attr/suwMarginSides</item>
+ <item name="android:navigationBarColor" tools:ignore="NewApi">@android:color/black</item>
+ <item name="android:statusBarColor" tools:ignore="NewApi">@android:color/transparent</item>
+ <item name="android:textAppearanceListItemSmall" tools:ignore="NewApi">?attr/textAppearanceListItemSmall</item>
+ <item name="android:textColorLink">@color/suw_link_color_light</item>
+ <item name="android:windowAnimationStyle">@style/Animation.SuwWindowAnimation</item>
+ <item name="android:windowDisablePreview">true</item>
+ <item name="android:windowSoftInputMode">adjustResize</item>
+
+ <item name="colorAccent">@color/suw_color_accent_glif_light</item>
+ <item name="colorPrimary">@color/suw_color_accent_glif_light</item>
+ <item name="listPreferredItemPaddingLeft">?attr/suwMarginSides</item>
+ <item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
+ <item name="suwColorPrimary">?attr/colorPrimary</item>
+ <item name="suwDividerInset">@dimen/suw_items_glif_icon_divider_inset</item>
+ <item name="suwGlifHeaderGravity">start</item>
+ <item name="suwItemDescriptionStyle">@style/SuwItemContainer.Description.Glif</item>
+ <item name="suwListItemIconColor">@color/suw_list_item_icon_color_light</item>
+ <item name="suwMarginSides">@dimen/suw_glif_margin_sides</item>
+ <item name="suwScrollIndicators">bottom</item>
+ <item name="textAppearanceListItem">@style/TextAppearance.SuwGlifItemTitle</item>
+ <item name="textAppearanceListItemSmall">@style/TextAppearance.SuwGlifItemSummary</item>
+ </style>
+
+ <!-- Content styles -->
+
+ <style name="TextAppearance.SuwDescription" parent="TextAppearance.AppCompat.Medium">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">@dimen/suw_description_text_size</item>
+ </style>
+
+ <!-- Items styles -->
+
+ <style name="SuwItemContainer">
+ <item name="android:minHeight">?android:attr/listPreferredItemHeight</item>
+ <item name="android:paddingBottom">@dimen/suw_items_padding_vertical</item>
+ <item name="android:paddingEnd" tools:ignore="NewApi">?attr/listPreferredItemPaddingRight</item>
+ <item name="android:paddingLeft">?attr/listPreferredItemPaddingLeft</item>
+ <item name="android:paddingRight">?attr/listPreferredItemPaddingRight</item>
+ <item name="android:paddingStart" tools:ignore="NewApi">?attr/listPreferredItemPaddingLeft</item>
+ <item name="android:paddingTop">@dimen/suw_items_padding_vertical</item>
+ </style>
+
+ <style name="SuwItemTitle">
+ <item name="android:textAppearance">?attr/textAppearanceListItem</item>
+ </style>
+
+ <style name="SuwItemSummary">
+ <item name="android:textAppearance">?attr/textAppearanceListItemSmall</item>
+ </style>
+
+ <style name="SuwSwitchStyle">
+ <item name="android:paddingEnd" tools:ignore="NewApi">@dimen/suw_switch_padding_end</item>
+ <item name="android:paddingLeft">@dimen/suw_switch_padding_start</item>
+ <item name="android:paddingRight">@dimen/suw_switch_padding_end</item>
+ <item name="android:paddingStart" tools:ignore="NewApi">@dimen/suw_switch_padding_start</item>
+ </style>
+
+ <style name="SuwSwitchStyle.Divided" parent="SuwSwitchStyle">
+ <item name="android:paddingEnd" tools:ignore="NewApi">?attr/listPreferredItemPaddingRight</item>
+ <item name="android:paddingRight">?attr/listPreferredItemPaddingRight</item>
+ </style>
+
+ <!-- Button styles -->
+
+ <style name="SuwGlifButton.Primary" parent="Widget.AppCompat.Button.Colored">
+ <!-- This style can be applied to a button either as a "style" in XML, or as a theme in
+ ContextThemeWrapper. These self-referencing attributes make sure this is applied as
+ both to the button. -->
+ <item name="android:buttonStyle">@style/SuwGlifButton.Primary</item>
+ <item name="buttonStyle">@style/SuwGlifButton.Primary</item>
+
+ <!-- Values used in styles -->
+ <item name="android:minWidth">0dp</item>
+ <item name="android:paddingLeft">@dimen/suw_glif_button_padding</item>
+ <item name="android:paddingRight">@dimen/suw_glif_button_padding</item>
+ </style>
+
+ <style name="SuwGlifButton.Secondary" parent="Widget.AppCompat.Button.Borderless.Colored">
+ <!-- This style can be applied to a button either as a "style" in XML, or as a theme in
+ ContextThemeWrapper. These self-referencing attributes make sure this is applied as
+ both to the button. -->
+ <item name="android:buttonStyle">@style/SuwGlifButton.Secondary</item>
+ <item name="android:theme">@style/SuwGlifButton.Secondary</item>
+ <item name="buttonStyle">@style/SuwGlifButton.Secondary</item>
+
+ <!-- Values used in styles -->
+ <item name="android:minWidth">0dp</item>
+ <item name="android:paddingLeft">@dimen/suw_glif_button_padding</item>
+ <item name="android:paddingRight">@dimen/suw_glif_button_padding</item>
+
+ <!-- Values used in themes -->
+ <item name="android:colorControlHighlight" tools:targetApi="lollipop">@color/suw_flat_button_highlight</item>
+ <item name="colorControlHighlight">@color/suw_flat_button_highlight</item>
+ </style>
+
+ <!-- Card layout (for tablets) -->
+
+ <style name="TextAppearance.SuwCardTitle" parent="@style/TextAppearance.AppCompat.Display1">
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+
+ <!-- GLIF Card layout (for tablets) -->
+
+ <style name="SuwGlifCardBackground">
+ <item name="android:background">?attr/colorPrimary</item>
+ </style>
+
+ <!-- Navigation bar styles -->
+
+ <style name="SuwNavBarButtonStyle" parent="@android:style/Widget.Button">
+ <item name="android:background">?attr/suwNavBarButtonBackground</item>
+ <item name="android:drawablePadding">@dimen/suw_navbar_button_drawable_padding</item>
+ <item name="android:fontFamily" tools:ignore="NewApi">sans-serif</item>
+ <item name="android:minWidth">0dp</item>
+ <item name="android:paddingLeft">@dimen/suw_navbar_button_padding_sides</item>
+ <item name="android:paddingRight">@dimen/suw_navbar_button_padding_sides</item>
+ <item name="android:textAllCaps" tools:ignore="NewApi">true</item>
+ <item name="android:textColor">?attr/suwNavBarTextColor</item>
+ <item name="android:textSize">@dimen/suw_navbar_text_size</item>
+ </style>
+
+ <style name="SuwNavBarThemeDark" parent="SuwNavBarTheme">
+ <item name="suwNavBarBackgroundColor">@color/suw_navbar_bg_dark</item>
+ <item name="suwNavBarButtonBackground">@drawable/suw_navbar_btn_bg_dark</item>
+ </style>
+
+ <style name="SuwNavBarThemeLight" parent="SuwNavBarTheme">
+ <item name="suwNavBarBackgroundColor">@color/suw_navbar_bg_light</item>
+ <item name="suwNavBarButtonBackground">@drawable/suw_navbar_btn_bg_light</item>
+ </style>
+
+</resources>
diff --git a/library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java b/library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java
new file mode 100644
index 0000000..be9916e
--- /dev/null
+++ b/library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 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.setupwizardlib.items;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.view.CheckableLinearLayout;
+
+/**
+ * A switch item which is divided into two parts: the start (left for LTR) side shows the title and
+ * summary, and when that is clicked, will expand to show a longer summary. The end (right for LTR)
+ * side is a switch which can be toggled by the user.
+ *
+ * Note: It is highly recommended to use this item with recycler view rather than list view, because
+ * list view draws the touch ripple effect on top of the item, rather than letting the item handle
+ * it. Therefore you might see a double-ripple, one for the expandable area and one for the entire
+ * list item, when using this in list view.
+ */
+public class ExpandableSwitchItem extends SwitchItem
+ implements OnCheckedChangeListener, OnClickListener {
+
+ private CharSequence mCollapsedSummary;
+ private CharSequence mExpandedSummary;
+ private boolean mIsExpanded = false;
+
+ public ExpandableSwitchItem() {
+ super();
+ }
+
+ public ExpandableSwitchItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.SuwExpandableSwitchItem);
+ mCollapsedSummary = a.getText(R.styleable.SuwExpandableSwitchItem_suwCollapsedSummary);
+ mExpandedSummary = a.getText(R.styleable.SuwExpandableSwitchItem_suwExpandedSummary);
+ a.recycle();
+ }
+
+ @Override
+ protected int getDefaultLayoutResource() {
+ return R.layout.suw_items_expandable_switch;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mIsExpanded ? getExpandedSummary() : getCollapsedSummary();
+ }
+
+ /**
+ * @return True if the item is currently expanded.
+ */
+ public boolean isExpanded() {
+ return mIsExpanded;
+ }
+
+ /**
+ * Sets whether the item should be expanded.
+ */
+ public void setExpanded(boolean expanded) {
+ if (mIsExpanded == expanded) {
+ return;
+ }
+ mIsExpanded = expanded;
+ notifyItemChanged();
+ }
+
+ /**
+ * @return The summary shown when in collapsed state.
+ */
+ public CharSequence getCollapsedSummary() {
+ return mCollapsedSummary;
+ }
+
+ /**
+ * Sets the summary text shown when the item is collapsed. Corresponds to the
+ * {@code app:suwCollapsedSummary} XML attribute.
+ */
+ public void setCollapsedSummary(CharSequence collapsedSummary) {
+ mCollapsedSummary = collapsedSummary;
+ if (!isExpanded()) {
+ notifyChanged();
+ }
+ }
+
+ /**
+ * @return The summary shown when in expanded state.
+ */
+ public CharSequence getExpandedSummary() {
+ return mExpandedSummary;
+ }
+
+ /**
+ * Sets the summary text shown when the item is expanded. Corresponds to the
+ * {@code app:suwExpandedSummary} XML attribute.
+ */
+ public void setExpandedSummary(CharSequence expandedSummary) {
+ mExpandedSummary = expandedSummary;
+ if (isExpanded()) {
+ notifyChanged();
+ }
+ }
+
+ @Override
+ public void onBindView(View view) {
+ // TODO: If it is possible to detect, log a warning if this is being used with ListView.
+ super.onBindView(view);
+ View content = view.findViewById(R.id.suw_items_expandable_switch_content);
+ content.setOnClickListener(this);
+
+ if (content instanceof CheckableLinearLayout) {
+ ((CheckableLinearLayout) content).setChecked(isExpanded());
+ }
+
+ tintCompoundDrawables(view);
+ }
+
+ @Override
+ public void onClick(View v) {
+ setExpanded(!isExpanded());
+ }
+
+ // Tint the expand arrow with the text color
+ private void tintCompoundDrawables(View view) {
+ final TypedArray a = view.getContext()
+ .obtainStyledAttributes(new int[] {android.R.attr.textColorPrimary});
+ final ColorStateList tintColor = a.getColorStateList(0);
+ a.recycle();
+
+ if (tintColor != null) {
+ TextView titleView = (TextView) view.findViewById(R.id.suw_items_title);
+ for (Drawable drawable : titleView.getCompoundDrawables()) {
+ if (drawable != null) {
+ drawable.setColorFilter(tintColor.getDefaultColor(), Mode.SRC_IN);
+ }
+ }
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ for (Drawable drawable : titleView.getCompoundDrawablesRelative()) {
+ if (drawable != null) {
+ drawable.setColorFilter(tintColor.getDefaultColor(), Mode.SRC_IN);
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/library/gingerbread/src/com/android/setupwizardlib/items/SwitchItem.java b/library/gingerbread/src/com/android/setupwizardlib/items/SwitchItem.java
new file mode 100644
index 0000000..7459d77
--- /dev/null
+++ b/library/gingerbread/src/com/android/setupwizardlib/items/SwitchItem.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 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.setupwizardlib.items;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v7.widget.SwitchCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.CompoundButton;
+
+import com.android.setupwizardlib.R;
+
+/**
+ * An item that is displayed with a switch, with methods to manipulate and listen to the checked
+ * state of the switch. Note that by default, only click on the switch will change the on-off state.
+ * To change the switch state when tapping on the text, use the click handlers of list view or
+ * RecyclerItemAdapter with {@link #toggle(View)}.
+ */
+public class SwitchItem extends Item implements CompoundButton.OnCheckedChangeListener {
+
+ /**
+ * Listener for check state changes of this switch item.
+ */
+ public interface OnCheckedChangeListener {
+
+ /**
+ * Callback when checked state of a {@link SwitchItem} is changed.
+ *
+ * @see #setOnCheckedChangeListener(OnCheckedChangeListener)
+ */
+ void onCheckedChange(SwitchItem item, boolean isChecked);
+ }
+
+ private boolean mChecked = false;
+ private OnCheckedChangeListener mListener;
+
+ /**
+ * Creates a default switch item.
+ */
+ public SwitchItem() {
+ super();
+ }
+
+ /**
+ * Creates a switch item. This constructor is used for inflation from XML.
+ *
+ * @param context The context which this item is inflated in.
+ * @param attrs The XML attributes defined on the item.
+ */
+ public SwitchItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwSwitchItem);
+ mChecked = a.getBoolean(R.styleable.SuwSwitchItem_android_checked, false);
+ a.recycle();
+ }
+
+ /**
+ * Sets whether this item should be checked.
+ */
+ public void setChecked(boolean checked) {
+ if (mChecked != checked) {
+ mChecked = checked;
+ notifyItemChanged();
+ if (mListener != null) {
+ mListener.onCheckedChange(this, checked);
+ }
+ }
+ }
+
+ /**
+ * @return True if this switch item is currently checked.
+ */
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ @Override
+ protected int getDefaultLayoutResource() {
+ return R.layout.suw_items_switch;
+ }
+
+ /**
+ * Toggle the checked state of the switch, without invalidating the entire item.
+ *
+ * @param view The root view of this item, typically from the argument of onItemClick.
+ */
+ public void toggle(View view) {
+ mChecked = !mChecked;
+ final SwitchCompat switchView = (SwitchCompat) view.findViewById(R.id.suw_items_switch);
+ switchView.setChecked(mChecked);
+ }
+
+ @Override
+ public void onBindView(View view) {
+ super.onBindView(view);
+ final SwitchCompat switchView = (SwitchCompat) view.findViewById(R.id.suw_items_switch);
+ switchView.setOnCheckedChangeListener(null);
+ switchView.setChecked(mChecked);
+ switchView.setOnCheckedChangeListener(this);
+ switchView.setEnabled(isEnabled());
+ }
+
+ /**
+ * Sets a listener to listen for changes in checked state. This listener is invoked in both
+ * user toggling the switch and calls to {@link #setChecked(boolean)}.
+ */
+ public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mChecked = isChecked;
+ if (mListener != null) {
+ mListener.onCheckedChange(this, isChecked);
+ }
+ }
+}
diff --git a/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
new file mode 100644
index 0000000..e6fa497
--- /dev/null
+++ b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2016 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.setupwizardlib.util;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.text.Layout;
+import android.text.Spanned;
+import android.text.style.ClickableSpan;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.TextView;
+
+import java.util.List;
+
+/**
+ * An accessibility delegate that allows {@link android.text.style.ClickableSpan} to be focused and
+ * clicked by accessibility services.
+ *
+ * <p />Sample usage:
+ * <pre>
+ * LinkAccessibilityHelper mAccessibilityHelper;
+ *
+ * private void init() {
+ * mAccessibilityHelper = new LinkAccessibilityHelper(myTextView);
+ * ViewCompat.setAccessibilityDelegate(myTextView, mLinkHelper);
+ * }
+ *
+ * {@literal @}Override
+ * protected boolean dispatchHoverEvent({@literal @}NonNull MotionEvent event) {
+ * if (mAccessibilityHelper != null && mAccessibilityHelper.dispatchHoverEvent(event)) {
+ * return true;
+ * }
+ * return super.dispatchHoverEvent(event);
+ * }
+ * </pre>
+ *
+ * @see com.android.setupwizardlib.view.RichTextView
+ * @see android.support.v4.widget.ExploreByTouchHelper
+ */
+public class LinkAccessibilityHelper extends ExploreByTouchHelper {
+
+ private static final String TAG = "LinkAccessibilityHelper";
+
+ private final TextView mView;
+ private final Rect mTempRect = new Rect();
+
+ public LinkAccessibilityHelper(TextView view) {
+ super(view);
+ mView = view;
+ }
+
+ @Override
+ protected int getVirtualViewAt(float x, float y) {
+ final CharSequence text = mView.getText();
+ if (text instanceof Spanned) {
+ final Spanned spannedText = (Spanned) text;
+ final int offset = getOffsetForPosition(mView, x, y);
+ ClickableSpan[] linkSpans = spannedText.getSpans(offset, offset, ClickableSpan.class);
+ if (linkSpans.length == 1) {
+ ClickableSpan linkSpan = linkSpans[0];
+ return spannedText.getSpanStart(linkSpan);
+ }
+ }
+ return INVALID_ID;
+ }
+
+ @Override
+ protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+ final CharSequence text = mView.getText();
+ if (text instanceof Spanned) {
+ final Spanned spannedText = (Spanned) text;
+ ClickableSpan[] linkSpans = spannedText.getSpans(0, spannedText.length(),
+ ClickableSpan.class);
+ for (ClickableSpan span : linkSpans) {
+ virtualViewIds.add(spannedText.getSpanStart(span));
+ }
+ }
+ }
+
+ @Override
+ protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
+ final ClickableSpan span = getSpanForOffset(virtualViewId);
+ if (span != null) {
+ event.setContentDescription(getTextForSpan(span));
+ } else {
+ Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
+ event.setContentDescription(mView.getText());
+ }
+ }
+
+ @Override
+ protected void onPopulateNodeForVirtualView(int virtualViewId,
+ AccessibilityNodeInfoCompat info) {
+ final ClickableSpan span = getSpanForOffset(virtualViewId);
+ if (span != null) {
+ info.setContentDescription(getTextForSpan(span));
+ } else {
+ Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
+ info.setContentDescription(mView.getText());
+ }
+ info.setFocusable(true);
+ info.setClickable(true);
+ getBoundsForSpan(span, mTempRect);
+ if (mTempRect.isEmpty()) {
+ Log.e(TAG, "LinkSpan bounds is empty for: " + virtualViewId);
+ mTempRect.set(0, 0, 1, 1);
+ }
+ info.setBoundsInParent(mTempRect);
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
+ }
+
+ @Override
+ protected boolean onPerformActionForVirtualView(int virtualViewId, int action,
+ Bundle arguments) {
+ if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
+ ClickableSpan span = getSpanForOffset(virtualViewId);
+ if (span != null) {
+ span.onClick(mView);
+ return true;
+ } else {
+ Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
+ }
+ }
+ return false;
+ }
+
+ private ClickableSpan getSpanForOffset(int offset) {
+ CharSequence text = mView.getText();
+ if (text instanceof Spanned) {
+ Spanned spannedText = (Spanned) text;
+ ClickableSpan[] spans = spannedText.getSpans(offset, offset, ClickableSpan.class);
+ if (spans.length == 1) {
+ return spans[0];
+ }
+ }
+ return null;
+ }
+
+ private CharSequence getTextForSpan(ClickableSpan span) {
+ CharSequence text = mView.getText();
+ if (text instanceof Spanned) {
+ Spanned spannedText = (Spanned) text;
+ return spannedText.subSequence(spannedText.getSpanStart(span),
+ spannedText.getSpanEnd(span));
+ }
+ return text;
+ }
+
+ // Find the bounds of a span. If it spans multiple lines, it will only return the bounds for the
+ // section on the first line.
+ private Rect getBoundsForSpan(ClickableSpan span, Rect outRect) {
+ CharSequence text = mView.getText();
+ outRect.setEmpty();
+ if (text instanceof Spanned) {
+ final Layout layout = mView.getLayout();
+ if (layout != null) {
+ Spanned spannedText = (Spanned) text;
+ final int spanStart = spannedText.getSpanStart(span);
+ final int spanEnd = spannedText.getSpanEnd(span);
+ final float xStart = layout.getPrimaryHorizontal(spanStart);
+ final float xEnd = layout.getPrimaryHorizontal(spanEnd);
+ final int lineStart = layout.getLineForOffset(spanStart);
+ final int lineEnd = layout.getLineForOffset(spanEnd);
+ layout.getLineBounds(lineStart, outRect);
+ if (lineEnd == lineStart) {
+ // If the span is on a single line, adjust both the left and right bounds
+ // so outrect is exactly bounding the span.
+ outRect.left = (int) Math.min(xStart, xEnd);
+ outRect.right = (int) Math.max(xStart, xEnd);
+ } else {
+ // If the span wraps across multiple lines, only use the first line (as returned
+ // by layout.getLineBounds above), and adjust the "start" of outrect to where
+ // the span starts, leaving the "end" of outrect at the end of the line.
+ // ("start" being left for LTR, and right for RTL)
+ if (layout.getParagraphDirection(lineStart) == Layout.DIR_RIGHT_TO_LEFT) {
+ outRect.right = (int) xStart;
+ } else {
+ outRect.left = (int) xStart;
+ }
+ }
+
+ // Offset for padding
+ outRect.offset(mView.getTotalPaddingLeft(), mView.getTotalPaddingTop());
+ }
+ }
+ return outRect;
+ }
+
+ // Compat implementation of TextView#getOffsetForPosition().
+
+ private static int getOffsetForPosition(TextView view, float x, float y) {
+ if (view.getLayout() == null) return -1;
+ final int line = getLineAtCoordinate(view, y);
+ return getOffsetAtCoordinate(view, line, x);
+ }
+
+ private static float convertToLocalHorizontalCoordinate(TextView view, float x) {
+ x -= view.getTotalPaddingLeft();
+ // Clamp the position to inside of the view.
+ x = Math.max(0.0f, x);
+ x = Math.min(view.getWidth() - view.getTotalPaddingRight() - 1, x);
+ x += view.getScrollX();
+ return x;
+ }
+
+ private static int getLineAtCoordinate(TextView view, float y) {
+ y -= view.getTotalPaddingTop();
+ // Clamp the position to inside of the view.
+ y = Math.max(0.0f, y);
+ y = Math.min(view.getHeight() - view.getTotalPaddingBottom() - 1, y);
+ y += view.getScrollY();
+ return view.getLayout().getLineForVertical((int) y);
+ }
+
+ private static int getOffsetAtCoordinate(TextView view, int line, float x) {
+ x = convertToLocalHorizontalCoordinate(view, x);
+ return view.getLayout().getOffsetForHorizontal(line, x);
+ }
+}
diff --git a/library/gingerbread/src/com/android/setupwizardlib/view/NavigationBarButton.java b/library/gingerbread/src/com/android/setupwizardlib/view/NavigationBarButton.java
new file mode 100644
index 0000000..5172c47
--- /dev/null
+++ b/library/gingerbread/src/com/android/setupwizardlib/view/NavigationBarButton.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 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.setupwizardlib.view;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+/**
+ * Button for navigation bar, which includes tinting of its compound drawables to be used for dark
+ * and light themes.
+ */
+public class NavigationBarButton extends Button {
+
+ public NavigationBarButton(Context context) {
+ super(context);
+ init();
+ }
+
+ public NavigationBarButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ // Unfortunately, drawableStart and drawableEnd set through XML does not call the setter,
+ // so manually getting it and wrapping it in the compat drawable.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ Drawable[] drawables = getCompoundDrawablesRelative();
+ for (int i = 0; i < drawables.length; i++) {
+ if (drawables[i] != null) {
+ drawables[i] = TintedDrawable.wrap(drawables[i]);
+ }
+ }
+ setCompoundDrawablesRelativeWithIntrinsicBounds(drawables[0], drawables[1],
+ drawables[2], drawables[3]);
+ }
+ }
+
+ @Override
+ public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {
+ if (left != null) left = TintedDrawable.wrap(left);
+ if (top != null) top = TintedDrawable.wrap(top);
+ if (right != null) right = TintedDrawable.wrap(right);
+ if (bottom != null) bottom = TintedDrawable.wrap(bottom);
+ super.setCompoundDrawables(left, top, right, bottom);
+ tintDrawables();
+ }
+
+ @Override
+ public void setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end,
+ Drawable bottom) {
+ if (start != null) start = TintedDrawable.wrap(start);
+ if (top != null) top = TintedDrawable.wrap(top);
+ if (end != null) end = TintedDrawable.wrap(end);
+ if (bottom != null) bottom = TintedDrawable.wrap(bottom);
+ super.setCompoundDrawablesRelative(start, top, end, bottom);
+ tintDrawables();
+ }
+
+ @Override
+ public void setTextColor(ColorStateList colors) {
+ super.setTextColor(colors);
+ tintDrawables();
+ }
+
+ private void tintDrawables() {
+ final ColorStateList textColors = getTextColors();
+ if (textColors != null) {
+ for (Drawable drawable : getAllCompoundDrawables()) {
+ if (drawable instanceof TintedDrawable) {
+ ((TintedDrawable) drawable).setTintListCompat(textColors);
+ }
+ }
+ invalidate();
+ }
+ }
+
+ private Drawable[] getAllCompoundDrawables() {
+ Drawable[] drawables = new Drawable[6];
+ Drawable[] compoundDrawables = getCompoundDrawables();
+ drawables[0] = compoundDrawables[0]; // left
+ drawables[1] = compoundDrawables[1]; // top
+ drawables[2] = compoundDrawables[2]; // right
+ drawables[3] = compoundDrawables[3]; // bottom
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ Drawable[] compoundDrawablesRelative = getCompoundDrawablesRelative();
+ drawables[4] = compoundDrawablesRelative[0]; // start
+ drawables[5] = compoundDrawablesRelative[2]; // end
+ }
+ return drawables;
+ }
+
+ // TODO: Remove this class and use DrawableCompat.wrap() once we can use support library 22.1.0
+ // or above
+ private static class TintedDrawable extends LayerDrawable {
+
+ public static TintedDrawable wrap(Drawable drawable) {
+ if (drawable instanceof TintedDrawable) {
+ return (TintedDrawable) drawable;
+ }
+ return new TintedDrawable(drawable.mutate());
+ }
+
+ private ColorStateList mTintList = null;
+
+ TintedDrawable(Drawable wrapped) {
+ super(new Drawable[] { wrapped });
+ }
+
+ @Override
+ public boolean isStateful() {
+ return true;
+ }
+
+ @Override
+ public boolean setState(@NonNull int[] stateSet) {
+ boolean needsInvalidate = super.setState(stateSet);
+ boolean needsInvalidateForState = updateState();
+ return needsInvalidate || needsInvalidateForState;
+ }
+
+ public void setTintListCompat(ColorStateList colors) {
+ mTintList = colors;
+ if (updateState()) {
+ invalidateSelf();
+ }
+ }
+
+ private boolean updateState() {
+ if (mTintList != null) {
+ final int color = mTintList.getColorForState(getState(), 0);
+ setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ return true; // Needs invalidate
+ }
+ return false;
+ }
+ }
+}
diff --git a/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java b/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java
new file mode 100644
index 0000000..6ccedf0
--- /dev/null
+++ b/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 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.setupwizardlib.view;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.support.v4.view.ViewCompat;
+import android.text.Annotation;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ClickableSpan;
+import android.text.style.TextAppearanceSpan;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.span.LinkSpan;
+import com.android.setupwizardlib.span.SpanHelper;
+import com.android.setupwizardlib.util.LinkAccessibilityHelper;
+
+/**
+ * An extension of TextView that automatically replaces the annotation tags as specified in
+ * {@link SpanHelper#replaceSpan(android.text.Spannable, Object, Object)}
+ */
+public class RichTextView extends TextView {
+
+ /* static section */
+
+ private static final String TAG = "RichTextView";
+
+ private static final String ANNOTATION_LINK = "link";
+ private static final String ANNOTATION_TEXT_APPEARANCE = "textAppearance";
+
+ /**
+ * Replace &lt;annotation&gt; tags in strings to become their respective types. Currently 2
+ * types are supported:
+ * <ol>
+ * <li>&lt;annotation link="foobar"&gt; will create a
+ * {@link com.android.setupwizardlib.span.LinkSpan} that broadcasts with the key
+ * "foobar"</li>
+ * <li>&lt;annotation textAppearance="TextAppearance.FooBar"&gt; will create a
+ * {@link android.text.style.TextAppearanceSpan} with @style/TextAppearance.FooBar</li>
+ * </ol>
+ */
+ public static CharSequence getRichText(Context context, CharSequence text) {
+ if (text instanceof Spanned) {
+ final SpannableString spannable = new SpannableString(text);
+ final Annotation[] spans = spannable.getSpans(0, spannable.length(), Annotation.class);
+ for (Annotation span : spans) {
+ final String key = span.getKey();
+ if (ANNOTATION_TEXT_APPEARANCE.equals(key)) {
+ String textAppearance = span.getValue();
+ final int style = context.getResources()
+ .getIdentifier(textAppearance, "style", context.getPackageName());
+ if (style == 0) {
+ Log.w(TAG, "Cannot find resource: " + style);
+ }
+ final TextAppearanceSpan textAppearanceSpan =
+ new TextAppearanceSpan(context, style);
+ SpanHelper.replaceSpan(spannable, span, textAppearanceSpan);
+ } else if (ANNOTATION_LINK.equals(key)) {
+ LinkSpan link = new LinkSpan(span.getValue());
+ SpanHelper.replaceSpan(spannable, span, link);
+ }
+ }
+ return spannable;
+ }
+ return text;
+ }
+
+ /* non-static section */
+
+ private LinkAccessibilityHelper mAccessibilityHelper;
+
+ public RichTextView(Context context) {
+ super(context);
+ init();
+ }
+
+ public RichTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ mAccessibilityHelper = new LinkAccessibilityHelper(this);
+ ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
+ }
+
+ @Override
+ public void setText(CharSequence text, BufferType type) {
+ text = getRichText(getContext(), text);
+ // Set text first before doing anything else because setMovementMethod internally calls
+ // setText. This in turn ends up calling this method with mText as the first parameter
+ super.setText(text, type);
+ boolean hasLinks = hasLinks(text);
+
+ if (hasLinks) {
+ // When a TextView has a movement method, it will set the view to clickable. This makes
+ // View.onTouchEvent always return true and consumes the touch event, essentially
+ // nullifying any return values of MovementMethod.onTouchEvent.
+ // To still allow propagating touch events to the parent when this view doesn't have
+ // links, we only set the movement method here if the text contains links.
+ setMovementMethod(LinkMovementMethod.getInstance());
+ } else {
+ setMovementMethod(null);
+ }
+ // ExploreByTouchHelper automatically enables focus for RichTextView
+ // even though it may not have any links. Causes problems during talkback
+ // as individual TextViews consume touch events and thereby reducing the focus window
+ // shown by Talkback. Disable focus if there are no links
+ setFocusable(hasLinks);
+ }
+
+ private boolean hasLinks(CharSequence text) {
+ if (text instanceof Spanned) {
+ final ClickableSpan[] spans =
+ ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
+ return spans.length > 0;
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean dispatchHoverEvent(MotionEvent event) {
+ if (mAccessibilityHelper != null && mAccessibilityHelper.dispatchHoverEvent(event)) {
+ return true;
+ }
+ return super.dispatchHoverEvent(event);
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ // b/26765507 causes drawableStart and drawableEnd to not get the right state on M. As a
+ // workaround, set the state on those drawables directly.
+ final int[] state = getDrawableState();
+ for (Drawable drawable : getCompoundDrawablesRelative()) {
+ if (drawable != null) {
+ if (drawable.setState(state)) {
+ invalidateDrawable(drawable);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/items/ButtonItemDrawingTest.java b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/items/ButtonItemDrawingTest.java
new file mode 100644
index 0000000..74d3be6
--- /dev/null
+++ b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/items/ButtonItemDrawingTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 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.setupwizardlib.items;
+
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.UiThreadTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.test.util.DrawingTestHelper;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ButtonItemDrawingTest {
+
+ private static final int GOOGLE_BLUE = 0xff4285f4;
+
+ // These tests need to be run on UI thread because button uses ValueAnimator
+ @Rule
+ public UiThreadTestRule mUiThreadTestRule = new UiThreadTestRule();
+
+ private ViewGroup mParent;
+
+ @Before
+ public void setUp() throws Exception {
+ mParent = new LinearLayout(
+ DrawingTestHelper.createCanvasActivity(R.style.SuwThemeGlif_Light));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testColoredButtonTheme() {
+ TestButtonItem item = new TestButtonItem();
+ item.setTheme(R.style.SuwButtonItem_Colored);
+ item.setText("foobar");
+
+ final Button button = item.createButton(mParent);
+
+ DrawingTestHelper drawingTestHelper = new DrawingTestHelper(50, 50);
+ drawingTestHelper.drawView(button);
+
+ int googleBluePixelCount = 0;
+ for (int pixel : drawingTestHelper.getPixels()) {
+ if (pixel == GOOGLE_BLUE) {
+ googleBluePixelCount++;
+ }
+ }
+ assertTrue("> 10 pixels should be Google blue. Found " + googleBluePixelCount,
+ googleBluePixelCount > 10);
+ }
+
+ private static class TestButtonItem extends ButtonItem {
+
+ @Override
+ public Button createButton(ViewGroup parent) {
+ // Make this method public for testing
+ return super.createButton(parent);
+ }
+ }
+}
diff --git a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/LinkAccessibilityHelperTest.java b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/LinkAccessibilityHelperTest.java
new file mode 100644
index 0000000..a1d01fd
--- /dev/null
+++ b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/LinkAccessibilityHelperTest.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2016 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.setupwizardlib.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.text.BidiFormatter;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.text.SpannableStringBuilder;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.span.LinkSpan;
+import com.android.setupwizardlib.util.LinkAccessibilityHelper;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkAccessibilityHelperTest {
+
+ private static final LinkSpan LINK_SPAN = new LinkSpan("foobar");
+
+ private TextView mTextView;
+ private TestLinkAccessibilityHelper mHelper;
+
+ private DisplayMetrics mDisplayMetrics;
+
+ @Test
+ public void testGetVirtualViewAt() {
+ initTextView();
+ final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(15), dp2Px(10));
+ assertEquals("Virtual view ID should be 1", 1, virtualViewId);
+ }
+
+ @Test
+ public void testGetVirtualViewAtHost() {
+ initTextView();
+ final int virtualViewId = mHelper.getVirtualViewAt(dp2Px(100), dp2Px(100));
+ assertEquals("Virtual view ID should be INVALID_ID",
+ ExploreByTouchHelper.INVALID_ID, virtualViewId);
+ }
+
+ @Test
+ public void testGetVisibleVirtualViews() {
+ initTextView();
+ List<Integer> virtualViewIds = new ArrayList<>();
+ mHelper.getVisibleVirtualViews(virtualViewIds);
+
+ assertEquals("VisibleVirtualViews should be [1]",
+ Collections.singletonList(1), virtualViewIds);
+ }
+
+ @Test
+ public void testOnPopulateEventForVirtualView() {
+ initTextView();
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ mHelper.onPopulateEventForVirtualView(1, event);
+
+ // LinkSpan is set on substring(1, 2) of "Hello world" --> "e"
+ assertEquals("LinkSpan description should be \"e\"",
+ "e", event.getContentDescription().toString());
+
+ event.recycle();
+ }
+
+ @Test
+ public void testOnPopulateEventForVirtualViewHost() {
+ initTextView();
+ AccessibilityEvent event = AccessibilityEvent.obtain();
+ mHelper.onPopulateEventForVirtualView(ExploreByTouchHelper.INVALID_ID, event);
+
+ assertEquals("Host view description should be \"Hello world\"", "Hello world",
+ event.getContentDescription().toString());
+
+ event.recycle();
+ }
+
+ @Test
+ public void testOnPopulateNodeForVirtualView() {
+ initTextView();
+ AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+ mHelper.onPopulateNodeForVirtualView(1, info);
+
+ assertEquals("LinkSpan description should be \"e\"",
+ "e", info.getContentDescription().toString());
+ assertTrue("LinkSpan should be focusable", info.isFocusable());
+ assertTrue("LinkSpan should be clickable", info.isClickable());
+ Rect bounds = new Rect();
+ info.getBoundsInParent(bounds);
+ assertEquals("LinkSpan bounds should be (10.5dp, 0dp, 18.5dp, 20.5dp)",
+ new Rect(dp2Px(10.5f), dp2Px(0f), dp2Px(18.5f), dp2Px(20.5f)), bounds);
+
+ info.recycle();
+ }
+
+ @Test
+ public void testNullLayout() {
+ initTextView();
+ // Setting the padding will cause the layout to be null-ed out.
+ mTextView.setPadding(1, 1, 1, 1);
+
+ AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+ mHelper.onPopulateNodeForVirtualView(0, info);
+
+ Rect bounds = new Rect();
+ info.getBoundsInParent(bounds);
+ assertEquals("LinkSpan bounds should be (0, 0, 1, 1)",
+ new Rect(0, 0, 1, 1), bounds);
+
+ info.recycle();
+ }
+
+ @Test
+ public void testRtlLayout() {
+ SpannableStringBuilder ssb = new SpannableStringBuilder("מכונה בתרגום");
+ ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */);
+ initTextView(ssb);
+
+ AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+ mHelper.onPopulateNodeForVirtualView(1, info);
+
+ assertEquals("LinkSpan description should be \"כ\"",
+ "כ", info.getContentDescription().toString());
+ Rect bounds = new Rect();
+ info.getBoundsInParent(bounds);
+ assertEquals("LinkSpan bounds should be (481.5dp, 0dp, 489.5dp, 20.5dp)",
+ new Rect(dp2Px(481.5f), dp2Px(0f), dp2Px(489.5f), dp2Px(20.5f)), bounds);
+
+ info.recycle();
+ }
+
+ @Test
+ public void testMultilineLink() {
+ SpannableStringBuilder ssb = new SpannableStringBuilder(
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
+ + "Praesent accumsan efficitur eros eu porttitor.");
+ ssb.setSpan(LINK_SPAN, 51, 74, 0 /* flags */);
+ initTextView(ssb);
+
+ AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+ mHelper.onPopulateNodeForVirtualView(51, info);
+
+ assertEquals("LinkSpan description should match the span",
+ "elit. Praesent accumsan", info.getContentDescription().toString());
+ Rect bounds = new Rect();
+ info.getBoundsInParent(bounds);
+ assertEquals("LinkSpan bounds should match first line of the span",
+ new Rect(dp2Px(343f), dp2Px(0f), dp2Px(500f), dp2Px(19.5f)), bounds);
+
+ info.recycle();
+ }
+
+ @Test
+ public void testRtlMultilineLink() {
+ String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים "
+ + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד "
+ + "דפים המחשב מיזמים ב.";
+ SpannableStringBuilder ssb = new SpannableStringBuilder(iwLoremIpsum);
+ ssb.setSpan(LINK_SPAN, 50, 100, 0 /* flags */);
+ initTextView(ssb);
+
+ AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+ mHelper.onPopulateNodeForVirtualView(50, info);
+
+ assertEquals("LinkSpan description should match the span",
+ iwLoremIpsum.substring(50, 100),
+ info.getContentDescription().toString());
+ Rect bounds = new Rect();
+ info.getBoundsInParent(bounds);
+ assertEquals("LinkSpan bounds should match the first line of the span",
+ new Rect(dp2Px(0f), dp2Px(0f), dp2Px(150f), dp2Px(19.5f)), bounds);
+
+ info.recycle();
+ }
+
+ @Test
+ public void testBidiMultilineLink() {
+ String iwLoremIpsum = "אחר על רביעי אקטואליה. לוח דת אחרות המקובל רומנית, מיזמים מועמדים "
+ + "האנציקלופדיה בה צ'ט. מתן מה שנורו לערוך ייִדיש, בקר או החול אנתרופולוגיה, עוד "
+ + "דפים המחשב מיזמים ב.";
+ BidiFormatter formatter = BidiFormatter.getInstance(false /* rtlContext */);
+ SpannableStringBuilder ssb = new SpannableStringBuilder();
+ ssb.append("hello ").append(formatter.unicodeWrap(iwLoremIpsum)).append(" world");
+ ssb.setSpan(LINK_SPAN,
+ "hello ".length() + 2, // Add two for the characters added by BidiFormatter
+ "hello ".length() + 2 + iwLoremIpsum.length(),
+ 0 /* flags */);
+ initTextView(ssb);
+
+ AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+ mHelper.onPopulateNodeForVirtualView("hello ".length() + 2, info);
+
+ assertEquals("LinkSpan description should match the span",
+ iwLoremIpsum,
+ info.getContentDescription().toString());
+ Rect bounds = new Rect();
+ info.getBoundsInParent(bounds);
+ assertEquals("LinkSpan bounds should match the first line of the span",
+ new Rect(dp2Px(491.5f), dp2Px(0f), dp2Px(500f), dp2Px(19.5f)), bounds);
+
+ info.recycle();
+ }
+
+ private void initTextView() {
+ SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
+ ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */);
+ initTextView(ssb);
+ }
+
+ private void initTextView(CharSequence text) {
+ mTextView = new TextView(InstrumentationRegistry.getContext());
+ mTextView.setSingleLine(false);
+ mTextView.setText(text);
+ mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
+ mHelper = new TestLinkAccessibilityHelper(mTextView);
+
+ int measureExactly500dp = View.MeasureSpec.makeMeasureSpec(dp2Px(500),
+ View.MeasureSpec.EXACTLY);
+ mTextView.measure(measureExactly500dp, measureExactly500dp);
+ mTextView.layout(dp2Px(0), dp2Px(0), dp2Px(500), dp2Px(500));
+ }
+
+ private int dp2Px(float dp) {
+ if (mDisplayMetrics == null) {
+ mDisplayMetrics =
+ InstrumentationRegistry.getContext().getResources().getDisplayMetrics();
+ }
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDisplayMetrics);
+ }
+
+ private static class TestLinkAccessibilityHelper extends LinkAccessibilityHelper {
+
+ TestLinkAccessibilityHelper(TextView view) {
+ super(view);
+ }
+
+ @Override
+ public int getVirtualViewAt(float x, float y) {
+ return super.getVirtualViewAt(x, y);
+ }
+
+ @Override
+ public void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+ super.getVisibleVirtualViews(virtualViewIds);
+ }
+
+ @Override
+ public void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
+ super.onPopulateEventForVirtualView(virtualViewId, event);
+ }
+
+ @Override
+ public void onPopulateNodeForVirtualView(int virtualViewId,
+ AccessibilityNodeInfoCompat info) {
+ super.onPopulateNodeForVirtualView(virtualViewId, info);
+ }
+
+ @Override
+ public boolean onPerformActionForVirtualView(int virtualViewId, int action,
+ Bundle arguments) {
+ return super.onPerformActionForVirtualView(virtualViewId, action, arguments);
+ }
+ }
+}
diff --git a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/RichTextViewTest.java b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/RichTextViewTest.java
new file mode 100644
index 0000000..2e2b01e
--- /dev/null
+++ b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/RichTextViewTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 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.setupwizardlib.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.SuppressLint;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.Annotation;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.TextAppearanceSpan;
+
+import com.android.setupwizardlib.span.LinkSpan;
+import com.android.setupwizardlib.view.RichTextView;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RichTextViewTest {
+
+ @Test
+ public void testLinkAnnotation() {
+ Annotation link = new Annotation("link", "foobar");
+ SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
+ ssb.setSpan(link, 1, 2, 0 /* flags */);
+
+ RichTextView textView = new RichTextView(InstrumentationRegistry.getContext());
+ textView.setText(ssb);
+
+ final CharSequence text = textView.getText();
+ assertTrue("Text should be spanned", text instanceof Spanned);
+
+ Object[] spans = ((Spanned) text).getSpans(0, text.length(), Annotation.class);
+ assertEquals("Annotation should be removed " + Arrays.toString(spans), 0, spans.length);
+
+ spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class);
+ assertEquals("There should be one span " + Arrays.toString(spans), 1, spans.length);
+ assertTrue("The span should be a LinkSpan", spans[0] instanceof LinkSpan);
+ assertEquals("The LinkSpan should have id \"foobar\"",
+ "foobar", ((LinkSpan) spans[0]).getId());
+ }
+
+ @Test
+ public void testTextStyle() {
+ Annotation link = new Annotation("textAppearance", "foobar");
+ SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
+ ssb.setSpan(link, 1, 2, 0 /* flags */);
+
+ RichTextView textView = new RichTextView(InstrumentationRegistry.getContext());
+ textView.setText(ssb);
+
+ final CharSequence text = textView.getText();
+ assertTrue("Text should be spanned", text instanceof Spanned);
+
+ Object[] spans = ((Spanned) text).getSpans(0, text.length(), Annotation.class);
+ assertEquals("Annotation should be removed " + Arrays.toString(spans), 0, spans.length);
+
+ spans = ((Spanned) text).getSpans(0, text.length(), TextAppearanceSpan.class);
+ assertEquals("There should be one span " + Arrays.toString(spans), 1, spans.length);
+ assertTrue("The span should be a TextAppearanceSpan",
+ spans[0] instanceof TextAppearanceSpan);
+ }
+
+ @Test
+ public void testTextContaininingLinksAreFocusable() {
+ Annotation testLink = new Annotation("link", "value");
+ SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("Linked");
+ spannableStringBuilder.setSpan(testLink, 0, 3, 0);
+
+ RichTextView view = new RichTextView(InstrumentationRegistry.getContext());
+ view.setText(spannableStringBuilder);
+
+ assertTrue("TextView should be focusable since it contains spans", view.isFocusable());
+ }
+
+
+ @SuppressLint("SetTextI18n") // It's OK. This is just a test.
+ @Test
+ public void testTextContainingNoLinksAreNotFocusable() {
+ RichTextView textView = new RichTextView(InstrumentationRegistry.getContext());
+ textView.setText("Thou shall not be focusable!");
+
+ assertFalse("TextView should not be focusable since it does not contain any span",
+ textView.isFocusable());
+ }
+
+
+ // Based on the text contents of the text view, the "focusable" property of the element
+ // should also be automatically changed.
+ @SuppressLint("SetTextI18n") // It's OK. This is just a test.
+ @Test
+ public void testRichTxtViewFocusChangesWithTextChange() {
+ RichTextView textView = new RichTextView(InstrumentationRegistry.getContext());
+ textView.setText("Thou shall not be focusable!");
+
+ assertFalse(textView.isFocusable());
+
+ SpannableStringBuilder spannableStringBuilder =
+ new SpannableStringBuilder("I am focusable");
+ spannableStringBuilder.setSpan(new Annotation("link", "focus:on_me"), 0, 1, 0);
+ textView.setText(spannableStringBuilder);
+ assertTrue(textView.isFocusable());
+ }
+}
diff --git a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java
new file mode 100644
index 0000000..154339a
--- /dev/null
+++ b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.setupwizardlib.test.util;
+
+import android.support.v7.app.AppCompatActivity;
+
+/**
+ * Activity to test view and drawable drawing behaviors. This is used to make sure that the drawing
+ * behavior tested is the same as it would when inflated as part of an {@link AppCompatActivity},
+ * including custom layout inflaters and theme values that the support library injects to the
+ * activity.
+ *
+ * @see DrawingTestHelper
+ */
+public class DrawingTestActivity extends AppCompatActivity {
+}
diff --git a/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/ExpandableSwitchItemTest.java b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/ExpandableSwitchItemTest.java
new file mode 100644
index 0000000..0ae0737
--- /dev/null
+++ b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/ExpandableSwitchItemTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 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.setupwizardlib.items;
+
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.robolectric.RuntimeEnvironment.application;
+
+import android.support.v7.widget.SwitchCompat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.BuildConfig;
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+
+@RunWith(SuwLibRobolectricTestRunner.class)
+@Config(constants = BuildConfig.class, sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
+public class ExpandableSwitchItemTest {
+
+ private TextView mSummaryView;
+ private ExpandableSwitchItem mItem;
+
+ @Before
+ public void setUp() {
+ mItem = new ExpandableSwitchItem();
+ mItem.setTitle("TestTitle");
+ mItem.setCollapsedSummary("TestSummary");
+ mItem.setExpandedSummary("TestSummaryExpanded");
+ }
+
+ @Test
+ public void testInitialState() {
+ View view = createLayout();
+ mItem.onBindView(view);
+
+ assertEquals("Collapsed summary should be TestSummary",
+ "TestSummary", mItem.getCollapsedSummary());
+ assertEquals("Expanded summary should be TestSummaryExpanded",
+ "TestSummaryExpanded", mItem.getExpandedSummary());
+
+ assertEquals("Should be collapsed initially", "TestSummary", mItem.getSummary());
+ assertEquals("Summary view should display collapsed summary",
+ "TestSummary", mSummaryView.getText());
+ }
+
+ @Test
+ public void testExpanded() {
+ View view = createLayout();
+ mItem.onBindView(view);
+
+ mItem.setExpanded(true);
+
+ assertEquals("Collapsed summary should be TestSummary",
+ "TestSummary", mItem.getCollapsedSummary());
+ assertEquals("Expanded summary should be TestSummaryExpanded",
+ "TestSummaryExpanded", mItem.getExpandedSummary());
+
+ assertTrue("Should be expanded", mItem.isExpanded());
+ assertEquals("getSummary should be expanded summary",
+ "TestSummaryExpanded", mItem.getSummary());
+ }
+
+ @Test
+ public void testCollapsed() {
+ View view = createLayout();
+ mItem.onBindView(view);
+
+ mItem.setExpanded(true);
+ assertTrue("Should be expanded", mItem.isExpanded());
+
+ mItem.setExpanded(false);
+
+ assertEquals("Collapsed summary should be TestSummary",
+ "TestSummary", mItem.getCollapsedSummary());
+ assertEquals("Expanded summary should be TestSummaryExpanded",
+ "TestSummaryExpanded", mItem.getExpandedSummary());
+
+ assertFalse("Should be expanded", mItem.isExpanded());
+ assertEquals("getSummary should be collapsed summary",
+ "TestSummary", mItem.getSummary());
+ }
+
+ @Test
+ public void testClick() {
+ View view = createLayout();
+ mItem.onBindView(view);
+
+ assertFalse("Should not be expanded initially", mItem.isExpanded());
+
+ final View content = view.findViewById(R.id.suw_items_expandable_switch_content);
+ content.performClick();
+ assertTrue("Should be expanded after clicking", mItem.isExpanded());
+
+ content.performClick();
+ assertFalse("Should be collapsed again after clicking", mItem.isExpanded());
+ }
+
+ @Test
+ public void testDrawableState() {
+ final View view =
+ LayoutInflater.from(application).inflate(mItem.getLayoutResource(), null);
+ mItem.onBindView(view);
+
+ final View titleView = view.findViewById(R.id.suw_items_title);
+ assertThat("state_checked should not be set initially",
+ toArrayList(titleView.getDrawableState()),
+ not(hasItem(android.R.attr.state_checked)));
+
+ mItem.setExpanded(true);
+ mItem.onBindView(view);
+ assertThat("state_checked should not be set initially",
+ toArrayList(titleView.getDrawableState()),
+ hasItem(android.R.attr.state_checked));
+
+ mItem.setExpanded(false);
+ mItem.onBindView(view);
+ assertThat("state_checked should not be set initially",
+ toArrayList(titleView.getDrawableState()),
+ not(hasItem(android.R.attr.state_checked)));
+ }
+
+ private ArrayList<Integer> toArrayList(int[] array) {
+ ArrayList<Integer> arrayList = new ArrayList<>(array.length);
+ for (int i : array) {
+ arrayList.add(i);
+ }
+ return arrayList;
+ }
+
+ private ViewGroup createLayout() {
+ ViewGroup root = new FrameLayout(application);
+
+ ViewGroup content = new FrameLayout(application);
+ content.setId(R.id.suw_items_expandable_switch_content);
+ root.addView(content);
+
+ TextView titleView = new TextView(application);
+ titleView.setId(R.id.suw_items_title);
+ content.addView(titleView);
+
+ mSummaryView = new TextView(application);
+ mSummaryView.setId(R.id.suw_items_summary);
+ content.addView(mSummaryView);
+
+ FrameLayout iconContainer = new FrameLayout(application);
+ iconContainer.setId(R.id.suw_items_icon_container);
+ content.addView(iconContainer);
+
+ ImageView iconView = new ImageView(application);
+ iconView.setId(R.id.suw_items_icon);
+ iconContainer.addView(iconView);
+
+ SwitchCompat switchView = new SwitchCompat(application);
+ switchView.setId(R.id.suw_items_switch);
+ root.addView(switchView);
+
+ return root;
+ }
+}
diff --git a/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java
new file mode 100644
index 0000000..d391d80
--- /dev/null
+++ b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2015 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.setupwizardlib.items;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.robolectric.RuntimeEnvironment.application;
+
+import android.annotation.TargetApi;
+import android.os.Build.VERSION_CODES;
+import android.support.v7.widget.SwitchCompat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.setupwizardlib.BuildConfig;
+import com.android.setupwizardlib.R;
+import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(SuwLibRobolectricTestRunner.class)
+@Config(constants = BuildConfig.class, sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
+public class SwitchItemTest {
+
+ private SwitchCompat mSwitch;
+
+ @Test
+ public void testChecked() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
+
+ item.setChecked(true);
+
+ item.onBindView(view);
+
+ assertTrue("Switch should be checked", mSwitch.isChecked());
+ }
+
+ @Test
+ public void testNotChecked() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
+
+ item.setChecked(false);
+
+ item.onBindView(view);
+
+ assertFalse("Switch should be unchecked", mSwitch.isChecked());
+ }
+
+ @Test
+ public void testListener() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
+
+ item.setChecked(true);
+
+ final TestOnCheckedChangeListener listener = new TestOnCheckedChangeListener();
+ item.setOnCheckedChangeListener(listener);
+
+ item.onBindView(view);
+
+ assertTrue("Switch should be checked", mSwitch.isChecked());
+ mSwitch.setChecked(false);
+
+ assertTrue("Listener should be called", listener.mCalled);
+ assertFalse("Listener should not be checked", listener.mChecked);
+
+ mSwitch.setChecked(true);
+
+ assertTrue("Listener should be called", listener.mCalled);
+ assertTrue("Listener should be checked", listener.mChecked);
+ }
+
+ @Test
+ public void testRebind() {
+ SwitchItem item1 = new SwitchItem();
+ item1.setTitle("TestTitle1");
+ item1.setSummary("TestSummary1");
+ item1.setChecked(false);
+
+ SwitchItem item2 = new SwitchItem();
+ item2.setTitle("TestTitle2");
+ item2.setSummary("TestSummary2");
+ item2.setChecked(true);
+
+ View view = createLayout();
+
+ item1.onBindView(view);
+ item2.onBindView(view);
+
+ // Switch should be bound to item2, and therefore checked
+ assertTrue("Switch should be checked", mSwitch.isChecked());
+
+ // Switching the switch to false should change the checked state of item 2 only
+ mSwitch.setChecked(false);
+ assertFalse("Item1 should still be unchecked", item1.isChecked());
+ assertFalse("Item2 should not be checked", item2.isChecked());
+
+ // Switching the switch to true should change the checked state of item 2 only
+ mSwitch.setChecked(true);
+ assertFalse("Item1 should still be unchecked", item1.isChecked());
+ assertTrue("Item2 should be checked", item2.isChecked());
+ }
+
+ @Test
+ public void testListenerSetChecked() {
+ // Check that calling setChecked on the item will also call the listener.
+
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
+
+ item.setChecked(true);
+
+ final TestOnCheckedChangeListener listener = new TestOnCheckedChangeListener();
+ item.setOnCheckedChangeListener(listener);
+
+ item.onBindView(view);
+
+ assertTrue("Switch should be checked", mSwitch.isChecked());
+ item.setChecked(false);
+
+ assertTrue("Listener should be called", listener.mCalled);
+ assertFalse("Listener should not be checked", listener.mChecked);
+
+ item.setChecked(true);
+
+ assertTrue("Listener should be called", listener.mCalled);
+ assertTrue("Listener should be checked", listener.mChecked);
+ }
+
+ @Test
+ public void testToggle() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
+
+ item.setChecked(true);
+ item.onBindView(view);
+
+ assertTrue("Switch should be checked", mSwitch.isChecked());
+
+ item.toggle(view);
+
+ assertFalse("Switch should be unchecked", mSwitch.isChecked());
+ }
+
+ @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
+ @Config(minSdk = VERSION_CODES.JELLY_BEAN_MR1)
+ @Test
+ public void testAccessibility() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+
+ View view = LayoutInflater.from(application).inflate(R.layout.suw_items_switch, null);
+ item.onBindView(view);
+
+ final View titleView = view.findViewById(R.id.suw_items_title);
+ assertEquals("Title view should label for switch",
+ R.id.suw_items_switch, titleView.getLabelFor());
+ }
+
+ private ViewGroup createLayout() {
+ ViewGroup root = new FrameLayout(application);
+
+ TextView titleView = new TextView(application);
+ titleView.setId(R.id.suw_items_title);
+ root.addView(titleView);
+
+ TextView summaryView = new TextView(application);
+ summaryView.setId(R.id.suw_items_summary);
+ root.addView(summaryView);
+
+ FrameLayout iconContainer = new FrameLayout(application);
+ iconContainer.setId(R.id.suw_items_icon_container);
+ root.addView(iconContainer);
+
+ ImageView iconView = new ImageView(application);
+ iconView.setId(R.id.suw_items_icon);
+ iconContainer.addView(iconView);
+
+ mSwitch = new SwitchCompat(application);
+ mSwitch.setId(R.id.suw_items_switch);
+ root.addView(mSwitch);
+
+ return root;
+ }
+
+ private static class TestOnCheckedChangeListener implements SwitchItem.OnCheckedChangeListener {
+
+ boolean mCalled = false;
+ boolean mChecked = false;
+
+ @Override
+ public void onCheckedChange(SwitchItem item, boolean isChecked) {
+ mCalled = true;
+ mChecked = isChecked;
+ }
+ }
+}