summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2019-07-01 20:59:51 +0000
committerXin Li <delphij@google.com>2019-07-01 20:59:51 +0000
commitaa06a98b9387bf7cda7948de3f3949e82c151856 (patch)
treed4d0f1ccfa3d6b82ef0a0be0a353328a3001714d
parentf26a9e8e2e422b20c721e199961f11bc82dd250a (diff)
parent93dacd74efc365bc889773a7cca03adad1ded25d (diff)
downloadsetupwizard-aa06a98b9387bf7cda7948de3f3949e82c151856.tar.gz
DO NOT MERGE - Merge qt-dev-plus-aosp-without-vendor (5699924) into stage-aosp-mastertemp_140451723
Bug: 134405016 Change-Id: I5e74b54945db4e896b45312ec51d2a4facc01c55
-rw-r--r--PREUPLOAD.cfg3
-rw-r--r--library/LICENSE202
-rw-r--r--library/gingerbread/AndroidManifest.xml (renamed from navigationbar/res/drawable/setup_wizard_navbar_ic_next.xml)17
-rw-r--r--library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.pngbin191 -> 189 bytes
-rw-r--r--library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.pngbin257 -> 252 bytes
-rw-r--r--library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.pngbin192 -> 187 bytes
-rw-r--r--library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.pngbin208 -> 197 bytes
-rw-r--r--library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.pngbin280 -> 277 bytes
-rw-r--r--library/gingerbread/res/layout/suw_items_switch.xml10
-rw-r--r--library/gingerbread/res/layout/suw_items_switch_verbose.xml80
-rw-r--r--library/gingerbread/res/values-v21/styles.xml27
-rw-r--r--library/gingerbread/res/values/styles.xml19
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java239
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/items/SwitchItem.java178
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java467
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/view/NavigationBarButton.java233
-rw-r--r--library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java318
-rw-r--r--library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/items/ButtonItemDrawingTest.java129
-rw-r--r--library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java3
-rw-r--r--library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java602
-rw-r--r--library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/ExpandableSwitchItemTest.java247
-rw-r--r--library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java312
-rw-r--r--library/gingerbread/test/robotest/src/com/android/setupwizardlib/util/DimensionConsistencyTest.java51
-rw-r--r--library/grandfathered_lint_checks.txt0
-rw-r--r--library/main/res/color-v23/suw_flat_button_highlight.xml2
-rw-r--r--library/main/res/values-as/strings.xml23
-rw-r--r--library/main/res/values-hi/strings.xml2
-rw-r--r--library/main/res/values-mr/strings.xml2
-rw-r--r--library/main/res/values-night/styles.xml26
-rw-r--r--library/main/res/values-or/strings.xml23
-rw-r--r--library/main/res/values-v21/styles.xml6
-rw-r--r--library/main/res/values/attrs.xml1
-rw-r--r--library/main/res/values/dimens.xml5
-rw-r--r--library/main/res/values/styles.xml13
-rw-r--r--library/main/src/com/android/setupwizardlib/GlifLayout.java448
-rw-r--r--library/main/src/com/android/setupwizardlib/GlifListLayout.java236
-rw-r--r--library/main/src/com/android/setupwizardlib/GlifPatternDrawable.java489
-rw-r--r--library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java36
-rw-r--r--library/main/src/com/android/setupwizardlib/SetupWizardLayout.java741
-rw-r--r--library/main/src/com/android/setupwizardlib/SetupWizardListLayout.java249
-rw-r--r--library/main/src/com/android/setupwizardlib/TemplateLayout.java411
-rw-r--r--library/main/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetector.java147
-rw-r--r--library/main/src/com/android/setupwizardlib/items/AbstractItem.java64
-rw-r--r--library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java195
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ButtonBarItem.java147
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ButtonItem.java244
-rw-r--r--library/main/src/com/android/setupwizardlib/items/IItem.java42
-rw-r--r--library/main/src/com/android/setupwizardlib/items/Item.java284
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ItemAdapter.java246
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ItemGroup.java533
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java113
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ItemInflater.java32
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ReflectionInflater.java201
-rw-r--r--library/main/src/com/android/setupwizardlib/items/SimpleInflater.java283
-rw-r--r--library/main/src/com/android/setupwizardlib/span/LinkSpan.java197
-rw-r--r--library/main/src/com/android/setupwizardlib/span/SpanHelper.java20
-rw-r--r--library/main/src/com/android/setupwizardlib/template/ButtonFooterMixin.java259
-rw-r--r--library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java69
-rw-r--r--library/main/src/com/android/setupwizardlib/template/HeaderMixin.java110
-rw-r--r--library/main/src/com/android/setupwizardlib/template/IconMixin.java148
-rw-r--r--library/main/src/com/android/setupwizardlib/template/ListMixin.java328
-rw-r--r--library/main/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegate.java90
-rw-r--r--library/main/src/com/android/setupwizardlib/template/Mixin.java3
-rw-r--r--library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java93
-rw-r--r--library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java182
-rw-r--r--library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java418
-rw-r--r--library/main/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegate.java75
-rw-r--r--library/main/src/com/android/setupwizardlib/util/DrawableLayoutDirectionHelper.java114
-rw-r--r--library/main/src/com/android/setupwizardlib/util/FallbackThemeWrapper.java48
-rw-r--r--library/main/src/com/android/setupwizardlib/util/Partner.java300
-rw-r--r--library/main/src/com/android/setupwizardlib/util/ResultCodes.java8
-rw-r--r--library/main/src/com/android/setupwizardlib/util/SystemBarHelper.java599
-rw-r--r--library/main/src/com/android/setupwizardlib/util/ThemeResolver.java219
-rw-r--r--library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java658
-rw-r--r--library/main/src/com/android/setupwizardlib/view/BottomScrollView.java131
-rw-r--r--library/main/src/com/android/setupwizardlib/view/ButtonBarLayout.java142
-rw-r--r--library/main/src/com/android/setupwizardlib/view/CheckableLinearLayout.java97
-rw-r--r--library/main/src/com/android/setupwizardlib/view/FillContentLayout.java145
-rw-r--r--library/main/src/com/android/setupwizardlib/view/Illustration.java341
-rw-r--r--library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java467
-rw-r--r--library/main/src/com/android/setupwizardlib/view/IntrinsicSizeFrameLayout.java104
-rw-r--r--library/main/src/com/android/setupwizardlib/view/NavigationBar.java199
-rw-r--r--library/main/src/com/android/setupwizardlib/view/StatusBarBackgroundLayout.java116
-rw-r--r--library/main/src/com/android/setupwizardlib/view/StickyHeaderListView.java215
-rw-r--r--library/main/src/com/android/setupwizardlib/view/StickyHeaderScrollView.java125
-rw-r--r--library/main/src/com/android/setupwizardlib/view/TouchableMovementMethod.java86
-rw-r--r--library/platform/AndroidManifest.xml (renamed from navigationbar/res/drawable/setup_wizard_navbar_ic_back.xml)17
-rw-r--r--library/platform/res/values-v27/styles.xml15
-rw-r--r--library/platform/src/com/android/setupwizardlib/view/NavigationBarButton.java12
-rw-r--r--library/platform/src/com/android/setupwizardlib/view/RichTextView.java245
-rw-r--r--library/platform/test/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java3
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/DividerItemDecoration.java356
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/GlifPreferenceLayout.java103
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/GlifRecyclerLayout.java294
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/SetupWizardPreferenceLayout.java98
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/SetupWizardRecyclerLayout.java298
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/items/ItemViewHolder.java70
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/items/RecyclerItemAdapter.java401
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/template/RecyclerMixin.java393
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegate.java84
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/view/HeaderRecyclerView.java408
-rw-r--r--library/recyclerview/src/com/android/setupwizardlib/view/StickyHeaderRecyclerView.java174
-rw-r--r--library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/items/RecyclerItemAdapterTest.java218
-rw-r--r--library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/template/RecyclerMixinTest.java176
-rw-r--r--library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/DividerItemDecorationTest.java334
-rw-r--r--library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifPreferenceLayoutTest.java116
-rw-r--r--library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifRecyclerLayoutTest.java250
-rw-r--r--library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/HeaderRecyclerViewTest.java259
-rw-r--r--library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardPreferenceLayoutTest.java118
-rw-r--r--library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardRecyclerLayoutTest.java257
-rw-r--r--library/recyclerview/test/robotest/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegateTest.java95
-rw-r--r--library/rules.gradle2
-rw-r--r--library/self.gradle8
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/TemplateLayoutTest.java111
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/template/ButtonFooterMixinTest.java256
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/template/ColoredHeaderMixinTest.java89
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/template/HeaderMixinTest.java119
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/template/IconMixinTest.java189
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/template/ListMixinTest.java204
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/template/NavigationBarMixinTest.java107
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/template/ProgressBarMixinTest.java212
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/template/TemplateLayoutMixinTest.java51
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/BottomScrollViewTest.java146
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/ButtonBarItemTest.java175
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/DrawableLayoutDirectionHelperTest.java189
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/GlifLayoutTest.java177
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/GlifListLayoutTest.java180
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/GlifPatternDrawableTest.java212
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/IllustrationTest.java53
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/ItemAdapterTest.java116
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/ItemInflaterTest.java45
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/ItemLayoutTest.java86
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/ItemTest.java298
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/ReflectionInflaterTest.java79
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardLayoutTest.java390
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardListLayoutTest.java171
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/SimpleInflaterTest.java47
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/SpanHelperTest.java28
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/StatusBarBackgroundLayoutTest.java70
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/SystemBarHelperTest.java432
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestHelper.java106
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/test/util/MockWindow.java491
-rw-r--r--library/test/instrumentation/src/com/android/setupwizardlib/util/FallbackThemeWrapperTest.java60
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java631
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java121
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java275
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java545
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/robolectric/ExternalResources.java160
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/robolectric/SuwLibRobolectricTestRunner.java35
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowLog.java51
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java144
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java128
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java246
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java81
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java154
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java118
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java75
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java319
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/util/ThemeResolverTest.java216
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java618
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java103
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java383
-rw-r--r--library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java358
-rw-r--r--navigationbar/Android.bp7
-rw-r--r--navigationbar/AndroidManifest.xml20
-rw-r--r--navigationbar/common.mk17
-rw-r--r--navigationbar/project.properties1
-rw-r--r--navigationbar/res/drawable/setup_wizard_navbar_btn_bg.xml19
-rw-r--r--navigationbar/res/layout/setup_wizard_navbar_layout.xml41
-rw-r--r--navigationbar/res/values-af/strings.xml6
-rw-r--r--navigationbar/res/values-am/strings.xml6
-rw-r--r--navigationbar/res/values-ar/strings.xml6
-rw-r--r--navigationbar/res/values-az/strings.xml6
-rw-r--r--navigationbar/res/values-b+sr+Latn/strings.xml6
-rw-r--r--navigationbar/res/values-be/strings.xml6
-rw-r--r--navigationbar/res/values-bg/strings.xml6
-rw-r--r--navigationbar/res/values-bn/strings.xml6
-rw-r--r--navigationbar/res/values-bs/strings.xml6
-rw-r--r--navigationbar/res/values-ca/strings.xml6
-rw-r--r--navigationbar/res/values-cs/strings.xml6
-rw-r--r--navigationbar/res/values-da/strings.xml6
-rw-r--r--navigationbar/res/values-de/strings.xml6
-rw-r--r--navigationbar/res/values-el/strings.xml6
-rw-r--r--navigationbar/res/values-en-rAU/strings.xml6
-rw-r--r--navigationbar/res/values-en-rCA/strings.xml6
-rw-r--r--navigationbar/res/values-en-rGB/strings.xml6
-rw-r--r--navigationbar/res/values-en-rIN/strings.xml6
-rw-r--r--navigationbar/res/values-en-rXC/strings.xml6
-rw-r--r--navigationbar/res/values-es-rUS/strings.xml6
-rw-r--r--navigationbar/res/values-es/strings.xml6
-rw-r--r--navigationbar/res/values-et/strings.xml6
-rw-r--r--navigationbar/res/values-eu/strings.xml6
-rw-r--r--navigationbar/res/values-fa/strings.xml6
-rw-r--r--navigationbar/res/values-fi/strings.xml6
-rw-r--r--navigationbar/res/values-fr-rCA/strings.xml6
-rw-r--r--navigationbar/res/values-fr/strings.xml6
-rw-r--r--navigationbar/res/values-gl/strings.xml6
-rw-r--r--navigationbar/res/values-gu/strings.xml6
-rw-r--r--navigationbar/res/values-hi/strings.xml6
-rw-r--r--navigationbar/res/values-hr/strings.xml6
-rw-r--r--navigationbar/res/values-hu/strings.xml6
-rw-r--r--navigationbar/res/values-hy/strings.xml6
-rw-r--r--navigationbar/res/values-in/strings.xml6
-rw-r--r--navigationbar/res/values-is/strings.xml6
-rw-r--r--navigationbar/res/values-it/strings.xml6
-rw-r--r--navigationbar/res/values-iw/strings.xml6
-rw-r--r--navigationbar/res/values-ja/strings.xml6
-rw-r--r--navigationbar/res/values-ka/strings.xml6
-rw-r--r--navigationbar/res/values-kk/strings.xml6
-rw-r--r--navigationbar/res/values-km/strings.xml6
-rw-r--r--navigationbar/res/values-kn/strings.xml6
-rw-r--r--navigationbar/res/values-ko/strings.xml6
-rw-r--r--navigationbar/res/values-ky/strings.xml6
-rw-r--r--navigationbar/res/values-lo/strings.xml6
-rw-r--r--navigationbar/res/values-lt/strings.xml6
-rw-r--r--navigationbar/res/values-lv/strings.xml6
-rw-r--r--navigationbar/res/values-mk/strings.xml6
-rw-r--r--navigationbar/res/values-ml/strings.xml6
-rw-r--r--navigationbar/res/values-mn/strings.xml6
-rw-r--r--navigationbar/res/values-mr/strings.xml6
-rw-r--r--navigationbar/res/values-ms/strings.xml6
-rw-r--r--navigationbar/res/values-my/strings.xml6
-rw-r--r--navigationbar/res/values-nb/strings.xml6
-rw-r--r--navigationbar/res/values-ne/strings.xml6
-rw-r--r--navigationbar/res/values-nl/strings.xml6
-rw-r--r--navigationbar/res/values-pa/strings.xml6
-rw-r--r--navigationbar/res/values-pl/strings.xml6
-rw-r--r--navigationbar/res/values-pt-rBR/strings.xml6
-rw-r--r--navigationbar/res/values-pt-rPT/strings.xml6
-rw-r--r--navigationbar/res/values-pt/strings.xml6
-rw-r--r--navigationbar/res/values-ro/strings.xml6
-rw-r--r--navigationbar/res/values-ru/strings.xml6
-rw-r--r--navigationbar/res/values-si/strings.xml6
-rw-r--r--navigationbar/res/values-sk/strings.xml6
-rw-r--r--navigationbar/res/values-sl/strings.xml6
-rw-r--r--navigationbar/res/values-sq/strings.xml6
-rw-r--r--navigationbar/res/values-sr/strings.xml6
-rw-r--r--navigationbar/res/values-sv/strings.xml6
-rw-r--r--navigationbar/res/values-sw/strings.xml6
-rw-r--r--navigationbar/res/values-ta/strings.xml6
-rw-r--r--navigationbar/res/values-te/strings.xml6
-rw-r--r--navigationbar/res/values-th/strings.xml6
-rw-r--r--navigationbar/res/values-tl/strings.xml6
-rw-r--r--navigationbar/res/values-tr/strings.xml6
-rw-r--r--navigationbar/res/values-uk/strings.xml6
-rw-r--r--navigationbar/res/values-ur/strings.xml6
-rw-r--r--navigationbar/res/values-uz/strings.xml6
-rw-r--r--navigationbar/res/values-vi/strings.xml6
-rw-r--r--navigationbar/res/values-zh-rCN/strings.xml6
-rw-r--r--navigationbar/res/values-zh-rHK/strings.xml6
-rw-r--r--navigationbar/res/values-zh-rTW/strings.xml6
-rw-r--r--navigationbar/res/values-zu/strings.xml6
-rw-r--r--navigationbar/res/values/colors.xml7
-rw-r--r--navigationbar/res/values/dimens.xml9
-rw-r--r--navigationbar/res/values/strings.xml9
-rw-r--r--navigationbar/res/values/styles.xml43
-rw-r--r--navigationbar/src/com/android/setupwizard/navigationbar/SetupWizardNavBar.java191
-rwxr-xr-xtools/build_for_build_server.sh2
-rw-r--r--tools/checkstyle/checkstyle.xml20
-rw-r--r--tools/checkstyle/checkstyle_suppression.xml14
260 files changed, 14767 insertions, 15072 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index b45eaff..e6fe0c4 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,7 +1,4 @@
[Hook Scripts]
-checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py
- --sha ${PREUPLOAD_COMMIT}
- --config_xml tools/checkstyle/checkstyle.xml
[Builtin Hooks]
commit_msg_test_field = true
diff --git a/library/LICENSE b/library/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/library/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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. \ No newline at end of file
diff --git a/navigationbar/res/drawable/setup_wizard_navbar_ic_next.xml b/library/gingerbread/AndroidManifest.xml
index 1b40776..bf7d42f 100644
--- a/navigationbar/res/drawable/setup_wizard_navbar_ic_next.xml
+++ b/library/gingerbread/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ 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.
@@ -14,15 +14,10 @@
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:autoMirrored="true"
- android:width="@dimen/setup_wizard_navbar_ic_intrinsic_size"
- android:height="@dimen/setup_wizard_navbar_ic_intrinsic_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="?attr/setup_wizard_navbar_text_color"
- android:pathData="M10,6 l-1.4,1.4 4.6,4.6 -4.6,4.6 1.4,1.4 6,-6z" />
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.setupwizardlib">
-</vector>
+ <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="28" />
+
+</manifest>
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
index 94016f4..a7084c5 100644
--- a/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_arrow.png
+++ b/library/gingerbread/res/drawable-xhdpi/suw_navbar_ic_down_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
index 17811ae..ed3c3b0 100644
--- a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_down_arrow.png
+++ 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
index 97fed92..be42712 100644
--- a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_left_arrow.png
+++ 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
index f874955..d7bc4e3 100644
--- a/library/gingerbread/res/drawable-xxhdpi/suw_navbar_ic_right_arrow.png
+++ 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
index cb6a422..dcc1f3c 100644
--- a/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png
+++ b/library/gingerbread/res/drawable-xxxhdpi/suw_navbar_ic_down_arrow.png
Binary files differ
diff --git a/library/gingerbread/res/layout/suw_items_switch.xml b/library/gingerbread/res/layout/suw_items_switch.xml
index 5296a62..5614044 100644
--- a/library/gingerbread/res/layout/suw_items_switch.xml
+++ b/library/gingerbread/res/layout/suw_items_switch.xml
@@ -17,17 +17,17 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- style="@style/SuwItemContainer.Verbose"
+ style="@style/SuwItemContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:clipToPadding="false"
+ android:baselineAligned="false"
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:layout_gravity="center_vertical"
android:gravity="start">
<ImageView
@@ -41,13 +41,13 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/suw_items_verbose_padding_bottom_extra"
+ android:layout_marginBottom="@dimen/suw_items_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"
+ style="@style/SuwItemTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
diff --git a/library/gingerbread/res/layout/suw_items_switch_verbose.xml b/library/gingerbread/res/layout/suw_items_switch_verbose.xml
new file mode 100644
index 0000000..8911acc
--- /dev/null
+++ b/library/gingerbread/res/layout/suw_items_switch_verbose.xml
@@ -0,0 +1,80 @@
+<?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:baselineAligned="false"
+ android:clipToPadding="false"
+ android:orientation="horizontal"
+ tools:ignore="UnusedResources">
+ <!-- Ignore UnusedResources: can be used by clients -->
+
+ <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>
+
+ <androidx.appcompat.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/values-v21/styles.xml b/library/gingerbread/res/values-v21/styles.xml
new file mode 100644
index 0000000..3c0c254
--- /dev/null
+++ b/library/gingerbread/res/values-v21/styles.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 Google Inc.
+
+ 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">
+
+ <!-- Button styles -->
+
+ <style name="SuwGlifButton.Tertiary" parent="SuwGlifButton.BaseTertiary">
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="textAllCaps" tools:targetApi="ice_cream_sandwich">false</item>
+ </style>
+
+</resources>
diff --git a/library/gingerbread/res/values/styles.xml b/library/gingerbread/res/values/styles.xml
index 241f037..b008e1e 100644
--- a/library/gingerbread/res/values/styles.xml
+++ b/library/gingerbread/res/values/styles.xml
@@ -41,6 +41,7 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwCardBackground">@drawable/suw_card_bg_dark</item>
<item name="suwDividerInsetEnd">0dp</item>
<item name="suwDividerInsetStart">@dimen/suw_items_icon_divider_inset</item>
@@ -75,6 +76,7 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwCardBackground">@drawable/suw_card_bg_light</item>
<item name="suwDividerInsetEnd">0dp</item>
<item name="suwDividerInsetStart">@dimen/suw_items_icon_divider_inset</item>
@@ -109,7 +111,8 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonCornerRadius">@dimen/suw_glif_button_corner_radius</item>
- <item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonFontFamily">sans-serif-medium</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwColorPrimary">?attr/colorPrimary</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -148,7 +151,8 @@
<item name="listPreferredItemPaddingRight">?attr/suwMarginSides</item>
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonCornerRadius">@dimen/suw_glif_button_corner_radius</item>
- <item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonFontFamily">sans-serif-medium</item>
+ <item name="suwButtonHighlightAlpha">0.12</item>
<item name="suwColorPrimary">?attr/colorPrimary</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -262,6 +266,13 @@
<item name="colorControlHighlight">@color/suw_flat_button_highlight</item>
</style>
+ <!-- Ignore UnusedResources: used by clients -->
+ <style name="SuwGlifButton.Tertiary"
+ parent="SuwGlifButton.BaseTertiary"
+ tools:ignore="UnusedResources">
+ <item name="textAllCaps" tools:targetApi="ice_cream_sandwich">false</item>
+ </style>
+
<!-- Card layout (for tablets) -->
<style name="TextAppearance.SuwCardTitle" parent="@style/TextAppearance.AppCompat.Display1">
@@ -279,6 +290,10 @@
<style name="SuwFourColorIndeterminateProgressBar" parent="SuwBase.ProgressBarLarge">
<item name="android:layout_gravity">center</item>
<item name="android:indeterminate">true</item>
+ <item name="android:paddingEnd" tools:targetApi="17" >@dimen/suw_glif_progress_bar_padding</item>
+ <item name="android:paddingLeft">@dimen/suw_glif_progress_bar_padding</item>
+ <item name="android:paddingRight">@dimen/suw_glif_progress_bar_padding</item>
+ <item name="android:paddingStart" tools:targetApi="17" >@dimen/suw_glif_progress_bar_padding</item>
</style>
<!-- Navigation bar styles -->
diff --git a/library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java b/library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java
index 71d1bb6..4b9347f 100644
--- a/library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java
+++ b/library/gingerbread/src/com/android/setupwizardlib/items/ExpandableSwitchItem.java
@@ -28,7 +28,6 @@ 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;
@@ -37,140 +36,130 @@ import com.android.setupwizardlib.view.CheckableLinearLayout;
* 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.
+ * <p>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;
+ implements OnCheckedChangeListener, OnClickListener {
+
+ private CharSequence collapsedSummary;
+ private CharSequence expandedSummary;
+ private boolean isExpanded = false;
+
+ public ExpandableSwitchItem() {
+ super();
+ }
+
+ public ExpandableSwitchItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwExpandableSwitchItem);
+ collapsedSummary = a.getText(R.styleable.SuwExpandableSwitchItem_suwCollapsedSummary);
+ expandedSummary = a.getText(R.styleable.SuwExpandableSwitchItem_suwExpandedSummary);
+ a.recycle();
+ }
+
+ @Override
+ protected int getDefaultLayoutResource() {
+ return R.layout.suw_items_expandable_switch;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return isExpanded ? getExpandedSummary() : getCollapsedSummary();
+ }
+
+ /** @return True if the item is currently expanded. */
+ public boolean isExpanded() {
+ return isExpanded;
+ }
+
+ /** Sets whether the item should be expanded. */
+ public void setExpanded(boolean expanded) {
+ if (isExpanded == expanded) {
+ return;
}
-
- @Override
- public CharSequence getSummary() {
- return mIsExpanded ? getExpandedSummary() : getCollapsedSummary();
+ isExpanded = expanded;
+ notifyItemChanged();
+ }
+
+ /** @return The summary shown when in collapsed state. */
+ public CharSequence getCollapsedSummary() {
+ return collapsedSummary;
+ }
+
+ /**
+ * Sets the summary text shown when the item is collapsed. Corresponds to the {@code
+ * app:suwCollapsedSummary} XML attribute.
+ */
+ public void setCollapsedSummary(CharSequence collapsedSummary) {
+ this.collapsedSummary = collapsedSummary;
+ if (!isExpanded()) {
+ notifyChanged();
}
-
- /**
- * @return True if the item is currently expanded.
- */
- public boolean isExpanded() {
- return mIsExpanded;
+ }
+
+ /** @return The summary shown when in expanded state. */
+ public CharSequence getExpandedSummary() {
+ return expandedSummary;
+ }
+
+ /**
+ * Sets the summary text shown when the item is expanded. Corresponds to the {@code
+ * app:suwExpandedSummary} XML attribute.
+ */
+ public void setExpandedSummary(CharSequence expandedSummary) {
+ this.expandedSummary = expandedSummary;
+ if (isExpanded()) {
+ notifyChanged();
}
+ }
- /**
- * Sets whether the item should be expanded.
- */
- public void setExpanded(boolean expanded) {
- if (mIsExpanded == expanded) {
- return;
- }
- mIsExpanded = expanded;
- notifyItemChanged();
- }
+ @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);
- /**
- * @return The summary shown when in collapsed state.
- */
- public CharSequence getCollapsedSummary() {
- return mCollapsedSummary;
+ if (content instanceof CheckableLinearLayout) {
+ ((CheckableLinearLayout) content).setChecked(isExpanded());
}
- /**
- * 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();
+ tintCompoundDrawables(view);
+
+ // Expandable switch item has focusability on the expandable layout on the left, and the
+ // switch on the right, but not the item itself.
+ view.setFocusable(false);
+ }
+
+ @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);
}
- }
-
- /**
- * @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);
-
- // Expandable switch item has focusability on the expandable layout on the left, and the
- // switch on the right, but not the item itself.
- view.setFocusable(false);
- }
-
- @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);
- }
- }
- }
-
+ }
+ 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
index 8d828ac..56fa742 100644
--- a/library/gingerbread/src/com/android/setupwizardlib/items/SwitchItem.java
+++ b/library/gingerbread/src/com/android/setupwizardlib/items/SwitchItem.java
@@ -18,12 +18,10 @@ package com.android.setupwizardlib.items;
import android.content.Context;
import android.content.res.TypedArray;
+import androidx.appcompat.widget.SwitchCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CompoundButton;
-
-import androidx.appcompat.widget.SwitchCompat;
-
import com.android.setupwizardlib.R;
/**
@@ -34,101 +32,93 @@ import com.android.setupwizardlib.R;
*/
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;
+ /** Listener for check state changes of this switch item. */
+ public interface OnCheckedChangeListener {
/**
- * Creates a default switch item.
- */
- public SwitchItem() {
- super();
- }
-
- /**
- * Creates a switch item. This constructor is used for inflation from XML.
+ * Callback when checked state of a {@link SwitchItem} is changed.
*
- * @param context The context which this item is inflated in.
- * @param attrs The XML attributes defined on the item.
+ * @see #setOnCheckedChangeListener(OnCheckedChangeListener)
*/
- 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();
+ void onCheckedChange(SwitchItem item, boolean isChecked);
+ }
+
+ private boolean checked = false;
+ private OnCheckedChangeListener listener;
+
+ /** 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);
+ checked = a.getBoolean(R.styleable.SuwSwitchItem_android_checked, false);
+ a.recycle();
+ }
+
+ /** Sets whether this item should be checked. */
+ public void setChecked(boolean checked) {
+ if (this.checked != checked) {
+ this.checked = checked;
+ notifyItemChanged();
+ if (listener != null) {
+ listener.onCheckedChange(this, checked);
+ }
}
-
- /**
- * 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);
- }
+ }
+
+ /** @return True if this switch item is currently checked. */
+ public boolean isChecked() {
+ return checked;
+ }
+
+ @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) {
+ checked = !checked;
+ final SwitchCompat switchView = (SwitchCompat) view.findViewById(R.id.suw_items_switch);
+ switchView.setChecked(checked);
+ }
+
+ @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(checked);
+ 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) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ checked = isChecked;
+ if (listener != null) {
+ listener.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
index 2a378e8..c416a9e 100644
--- a/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
+++ b/library/gingerbread/src/com/android/setupwizardlib/util/LinkAccessibilityHelper.java
@@ -19,6 +19,12 @@ package com.android.setupwizardlib.util;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.core.view.AccessibilityDelegateCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
import android.text.Layout;
import android.text.Spanned;
import android.text.style.ClickableSpan;
@@ -28,14 +34,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.core.view.AccessibilityDelegateCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
-import androidx.customview.widget.ExploreByTouchHelper;
-
import java.util.List;
/**
@@ -46,6 +44,7 @@ import java.util.List;
* support for ClickableSpan accessibility.
*
* <p>Sample usage:
+ *
* <pre>
* LinkAccessibilityHelper mAccessibilityHelper;
*
@@ -68,262 +67,260 @@ import java.util.List;
*/
public class LinkAccessibilityHelper extends AccessibilityDelegateCompat {
- private static final String TAG = "LinkAccessibilityHelper";
-
- private final AccessibilityDelegateCompat mDelegate;
-
- public LinkAccessibilityHelper(TextView view) {
- this(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
- // Platform support was added in O. This helper will be no-op
- ? new AccessibilityDelegateCompat()
- // Pre-O, we extend ExploreByTouchHelper to expose a virtual view hierarchy
- : new PreOLinkAccessibilityHelper(view));
- }
-
- @VisibleForTesting
- LinkAccessibilityHelper(@NonNull AccessibilityDelegateCompat delegate) {
- mDelegate = delegate;
- }
-
- @Override
- public void sendAccessibilityEvent(View host, int eventType) {
- mDelegate.sendAccessibilityEvent(host, eventType);
+ private static final String TAG = "LinkAccessibilityHelper";
+
+ private final AccessibilityDelegateCompat delegate;
+
+ public LinkAccessibilityHelper(TextView view) {
+ this(
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+ // Platform support was added in O. This helper will be no-op
+ ? new AccessibilityDelegateCompat()
+ // Pre-O, we extend ExploreByTouchHelper to expose a virtual view hierarchy
+ : new PreOLinkAccessibilityHelper(view));
+ }
+
+ @VisibleForTesting
+ LinkAccessibilityHelper(@NonNull AccessibilityDelegateCompat delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void sendAccessibilityEvent(View host, int eventType) {
+ delegate.sendAccessibilityEvent(host, eventType);
+ }
+
+ @Override
+ public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
+ delegate.sendAccessibilityEventUnchecked(host, event);
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ return delegate.dispatchPopulateAccessibilityEvent(host, event);
+ }
+
+ @Override
+ public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+ delegate.onPopulateAccessibilityEvent(host, event);
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+ delegate.onInitializeAccessibilityEvent(host, event);
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+ delegate.onInitializeAccessibilityNodeInfo(host, info);
+ }
+
+ @Override
+ public boolean onRequestSendAccessibilityEvent(
+ ViewGroup host, View child, AccessibilityEvent event) {
+ return delegate.onRequestSendAccessibilityEvent(host, child, event);
+ }
+
+ @Override
+ public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
+ return delegate.getAccessibilityNodeProvider(host);
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ return delegate.performAccessibilityAction(host, action, args);
+ }
+
+ /**
+ * Dispatches hover event to the virtual view hierarchy. This method should be called in {@link
+ * View#dispatchHoverEvent(MotionEvent)}.
+ *
+ * @see ExploreByTouchHelper#dispatchHoverEvent(MotionEvent)
+ */
+ public boolean dispatchHoverEvent(MotionEvent event) {
+ return delegate instanceof ExploreByTouchHelper
+ && ((ExploreByTouchHelper) delegate).dispatchHoverEvent(event);
+ }
+
+ @VisibleForTesting
+ static class PreOLinkAccessibilityHelper extends ExploreByTouchHelper {
+
+ private final Rect tempRect = new Rect();
+ private final TextView view;
+
+ PreOLinkAccessibilityHelper(TextView view) {
+ super(view);
+ this.view = view;
}
@Override
- public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
- mDelegate.sendAccessibilityEventUnchecked(host, event);
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
- return mDelegate.dispatchPopulateAccessibilityEvent(host, event);
- }
-
- @Override
- public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
- mDelegate.onPopulateAccessibilityEvent(host, event);
+ protected int getVirtualViewAt(float x, float y) {
+ final CharSequence text = view.getText();
+ if (text instanceof Spanned) {
+ final Spanned spannedText = (Spanned) text;
+ final int offset = getOffsetForPosition(view, x, y);
+ ClickableSpan[] linkSpans = spannedText.getSpans(offset, offset, ClickableSpan.class);
+ if (linkSpans.length == 1) {
+ ClickableSpan linkSpan = linkSpans[0];
+ return spannedText.getSpanStart(linkSpan);
+ }
+ }
+ return ExploreByTouchHelper.INVALID_ID;
}
@Override
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- mDelegate.onInitializeAccessibilityEvent(host, event);
+ protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+ final CharSequence text = view.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
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
- mDelegate.onInitializeAccessibilityNodeInfo(host, info);
+ 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(view.getText());
+ }
}
@Override
- public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
- AccessibilityEvent event) {
- return mDelegate.onRequestSendAccessibilityEvent(host, child, event);
+ 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(view.getText());
+ }
+ info.setFocusable(true);
+ info.setClickable(true);
+ getBoundsForSpan(span, tempRect);
+ if (tempRect.isEmpty()) {
+ Log.e(TAG, "LinkSpan bounds is empty for: " + virtualViewId);
+ tempRect.set(0, 0, 1, 1);
+ }
+ info.setBoundsInParent(tempRect);
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
}
@Override
- public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
- return mDelegate.getAccessibilityNodeProvider(host);
+ protected boolean onPerformActionForVirtualView(
+ int virtualViewId, int action, Bundle arguments) {
+ if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
+ ClickableSpan span = getSpanForOffset(virtualViewId);
+ if (span != null) {
+ span.onClick(view);
+ return true;
+ } else {
+ Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
+ }
+ }
+ return false;
}
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- return mDelegate.performAccessibilityAction(host, action, args);
+ private ClickableSpan getSpanForOffset(int offset) {
+ CharSequence text = view.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;
}
- /**
- * Dispatches hover event to the virtual view hierarchy. This method should be called in
- * {@link View#dispatchHoverEvent(MotionEvent)}.
- *
- * @see ExploreByTouchHelper#dispatchHoverEvent(MotionEvent)
- */
- public final boolean dispatchHoverEvent(MotionEvent event) {
- return mDelegate instanceof ExploreByTouchHelper
- && ((ExploreByTouchHelper) mDelegate).dispatchHoverEvent(event);
+ private CharSequence getTextForSpan(ClickableSpan span) {
+ CharSequence text = view.getText();
+ if (text instanceof Spanned) {
+ Spanned spannedText = (Spanned) text;
+ return spannedText.subSequence(
+ spannedText.getSpanStart(span), spannedText.getSpanEnd(span));
+ }
+ return text;
}
- @VisibleForTesting
- static class PreOLinkAccessibilityHelper extends ExploreByTouchHelper {
-
- private final Rect mTempRect = new Rect();
- private final TextView mView;
-
- PreOLinkAccessibilityHelper(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 ExploreByTouchHelper.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));
+ // 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 = view.getText();
+ outRect.setEmpty();
+ if (text instanceof Spanned) {
+ final Layout layout = view.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 {
- Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
- event.setContentDescription(mView.getText());
+ outRect.left = (int) xStart;
}
- }
-
- @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;
+ // Offset for padding
+ outRect.offset(view.getTotalPaddingLeft(), view.getTotalPaddingTop());
}
+ }
+ return outRect;
+ }
- // Compat implementation of TextView#getOffsetForPosition().
+ // 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 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 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 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);
- }
+ 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
index 872cc9f..b2d9d79 100644
--- a/library/gingerbread/src/com/android/setupwizardlib/view/NavigationBarButton.java
+++ b/library/gingerbread/src/com/android/setupwizardlib/view/NavigationBarButton.java
@@ -23,11 +23,10 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
+import androidx.annotation.NonNull;
import android.util.AttributeSet;
import android.widget.Button;
-import androidx.annotation.NonNull;
-
/**
* Button for navigation bar, which includes tinting of its compound drawables to be used for dark
* and light themes.
@@ -35,128 +34,144 @@ import androidx.annotation.NonNull;
@SuppressLint("AppCompatCustomView")
public class NavigationBarButton extends Button {
- public NavigationBarButton(Context context) {
- super(context);
- init();
+ 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]);
}
+ }
- public NavigationBarButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
+ @Override
+ public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {
+ if (left != null) {
+ left = TintedDrawable.wrap(left);
}
-
- 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]);
+ 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());
}
- @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();
+ private ColorStateList tintList = null;
+
+ TintedDrawable(Drawable wrapped) {
+ super(new Drawable[] {wrapped});
}
@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();
+ public boolean isStateful() {
+ return true;
}
@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();
- }
+ public boolean setState(@NonNull int[] stateSet) {
+ boolean needsInvalidate = super.setState(stateSet);
+ boolean needsInvalidateForState = updateState();
+ return needsInvalidate || needsInvalidateForState;
}
- 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;
+ public void setTintListCompat(ColorStateList colors) {
+ tintList = colors;
+ if (updateState()) {
+ invalidateSelf();
+ }
}
- // 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;
- }
+ private boolean updateState() {
+ if (tintList != null) {
+ final int color = tintList.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
index 1ee3219..5e50e7a 100644
--- a/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java
+++ b/library/gingerbread/src/com/android/setupwizardlib/view/RichTextView.java
@@ -20,6 +20,8 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
+import androidx.core.view.ViewCompat;
+import androidx.appcompat.widget.AppCompatTextView;
import android.text.Annotation;
import android.text.SpannableString;
import android.text.Spanned;
@@ -29,10 +31,6 @@ import android.text.style.TextAppearanceSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
-
-import androidx.appcompat.widget.AppCompatTextView;
-import androidx.core.view.ViewCompat;
-
import com.android.setupwizardlib.span.LinkSpan;
import com.android.setupwizardlib.span.LinkSpan.OnLinkClickListener;
import com.android.setupwizardlib.span.SpanHelper;
@@ -40,178 +38,178 @@ import com.android.setupwizardlib.util.LinkAccessibilityHelper;
import com.android.setupwizardlib.view.TouchableMovementMethod.TouchableLinkMovementMethod;
/**
- * An extension of TextView that automatically replaces the annotation tags as specified in
- * {@link SpanHelper#replaceSpan(android.text.Spannable, Object, Object)}
+ * 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 AppCompatTextView implements OnLinkClickListener {
- /* 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;
+ /* 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>&lt;annotation textAppearance="TextAppearance.FooBar"&gt; will create a {@link
+ * android.text.style.TextAppearanceSpan} with @style/TextAppearance.FooBar
+ * </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 text;
- }
-
- /* non-static section */
-
- private LinkAccessibilityHelper mAccessibilityHelper;
- private OnLinkClickListener mOnLinkClickListener;
-
- public RichTextView(Context context) {
- super(context);
- init();
- }
-
- public RichTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
+ }
+ return spannable;
}
-
- private void init() {
- mAccessibilityHelper = new LinkAccessibilityHelper(this);
- ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
+ return text;
+ }
+
+ /* non-static section */
+
+ private LinkAccessibilityHelper accessibilityHelper;
+ private OnLinkClickListener onLinkClickListener;
+
+ public RichTextView(Context context) {
+ super(context);
+ init();
+ }
+
+ public RichTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ accessibilityHelper = new LinkAccessibilityHelper(this);
+ ViewCompat.setAccessibilityDelegate(this, accessibilityHelper);
+ }
+
+ @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(TouchableLinkMovementMethod.getInstance());
+ } else {
+ setMovementMethod(null);
}
-
- @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(TouchableLinkMovementMethod.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);
- // Do not "reveal" (i.e. scroll to) this view when this view is focused. Since this view is
- // focusable in touch mode, we may be focused when the screen is first shown, and starting
- // a screen halfway scrolled down is confusing to the user.
- if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) {
- setRevealOnFocusHint(false);
- // setRevealOnFocusHint is a new API added in SDK 25. For lower SDK versions, do not
- // call setFocusableInTouchMode. We won't get touch effect on those earlier versions,
- // but the link will still work, and will prevent the scroll view from starting halfway
- // down the page.
- setFocusableInTouchMode(hasLinks);
- }
+ // 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);
+ // Do not "reveal" (i.e. scroll to) this view when this view is focused. Since this view is
+ // focusable in touch mode, we may be focused when the screen is first shown, and starting
+ // a screen halfway scrolled down is confusing to the user.
+ if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) {
+ setRevealOnFocusHint(false);
+ // setRevealOnFocusHint is a new API added in SDK 25. For lower SDK versions, do not
+ // call setFocusableInTouchMode. We won't get touch effect on those earlier versions,
+ // but the link will still work, and will prevent the scroll view from starting halfway
+ // down the page.
+ setFocusableInTouchMode(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;
+ private boolean hasLinks(CharSequence text) {
+ if (text instanceof Spanned) {
+ final ClickableSpan[] spans =
+ ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
+ return spans.length > 0;
}
-
- @Override
- @SuppressWarnings("ClickableViewAccessibility") // super.onTouchEvent is called
- public boolean onTouchEvent(MotionEvent event) {
- // Since View#onTouchEvent always return true if the view is clickable (which is the case
- // when a TextView has a movement method), override the implementation to allow the movement
- // method, if it implements TouchableMovementMethod, to say that the touch is not handled,
- // allowing the event to bubble up to the parent view.
- boolean superResult = super.onTouchEvent(event);
- MovementMethod movementMethod = getMovementMethod();
- if (movementMethod instanceof TouchableMovementMethod) {
- TouchableMovementMethod touchableMovementMethod =
- (TouchableMovementMethod) movementMethod;
- if (touchableMovementMethod.getLastTouchEvent() == event) {
- return touchableMovementMethod.isLastTouchEventHandled();
- }
- }
- return superResult;
+ return false;
+ }
+
+ @Override
+ @SuppressWarnings("ClickableViewAccessibility") // super.onTouchEvent is called
+ public boolean onTouchEvent(MotionEvent event) {
+ // Since View#onTouchEvent always return true if the view is clickable (which is the case
+ // when a TextView has a movement method), override the implementation to allow the movement
+ // method, if it implements TouchableMovementMethod, to say that the touch is not handled,
+ // allowing the event to bubble up to the parent view.
+ boolean superResult = super.onTouchEvent(event);
+ MovementMethod movementMethod = getMovementMethod();
+ if (movementMethod instanceof TouchableMovementMethod) {
+ TouchableMovementMethod touchableMovementMethod = (TouchableMovementMethod) movementMethod;
+ if (touchableMovementMethod.getLastTouchEvent() == event) {
+ return touchableMovementMethod.isLastTouchEventHandled();
+ }
}
+ return superResult;
+ }
- @Override
- protected boolean dispatchHoverEvent(MotionEvent event) {
- if (mAccessibilityHelper != null && mAccessibilityHelper.dispatchHoverEvent(event)) {
- return true;
- }
- return super.dispatchHoverEvent(event);
+ @Override
+ protected boolean dispatchHoverEvent(MotionEvent event) {
+ if (accessibilityHelper != null && accessibilityHelper.dispatchHoverEvent(event)) {
+ return true;
}
-
- @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);
- }
- }
- }
+ 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);
+ }
}
+ }
}
+ }
- public void setOnLinkClickListener(OnLinkClickListener listener) {
- mOnLinkClickListener = listener;
- }
+ public void setOnLinkClickListener(OnLinkClickListener listener) {
+ onLinkClickListener = listener;
+ }
- public OnLinkClickListener getOnLinkClickListener() {
- return mOnLinkClickListener;
- }
+ public OnLinkClickListener getOnLinkClickListener() {
+ return onLinkClickListener;
+ }
- @Override
- public boolean onLinkClick(LinkSpan span) {
- if (mOnLinkClickListener != null) {
- return mOnLinkClickListener.onLinkClick(span);
- }
- return false;
+ @Override
+ public boolean onLinkClick(LinkSpan span) {
+ if (onLinkClickListener != null) {
+ return onLinkClickListener.onLinkClick(span);
}
+ return false;
+ }
}
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
index f5b8253..7f51fa7 100644
--- a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/items/ButtonItemDrawingTest.java
+++ b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/items/ButtonItemDrawingTest.java
@@ -18,19 +18,16 @@ package com.android.setupwizardlib.items;
import static org.junit.Assert.assertTrue;
+import androidx.annotation.StyleRes;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
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 androidx.annotation.StyleRes;
-
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.test.util.DrawingTestHelper;
-
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,69 +36,65 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class ButtonItemDrawingTest {
- private static final int GLIF_ACCENT_COLOR = 0xff4285f4;
- private static final int GLIF_V3_ACCENT_COLOR = 0xff1a73e8;
-
- // These tests need to be run on UI thread because button uses ValueAnimator
- @Rule
- public UiThreadTestRule mUiThreadTestRule = new UiThreadTestRule();
-
- @Test
- @UiThreadTest
- public void drawButton_glif_shouldHaveAccentColoredButton()
- throws InstantiationException, IllegalAccessException {
- Button button = createButton(R.style.SuwThemeGlif_Light);
-
- DrawingTestHelper drawingTestHelper = new DrawingTestHelper(50, 50);
- drawingTestHelper.drawView(button);
-
- int accentPixelCount =
- countPixelsWithColor(drawingTestHelper.getPixels(), GLIF_ACCENT_COLOR);
- assertTrue("> 10 pixels should be #4285f4. Found " + accentPixelCount,
- accentPixelCount > 10);
- }
-
- @Test
- @UiThreadTest
- public void drawButton_glifV3_shouldHaveAccentColoredButton()
- throws InstantiationException, IllegalAccessException {
- Button button = createButton(R.style.SuwThemeGlifV3_Light);
-
- DrawingTestHelper drawingTestHelper = new DrawingTestHelper(50, 50);
- drawingTestHelper.drawView(button);
-
- int accentPixelCount =
- countPixelsWithColor(drawingTestHelper.getPixels(), GLIF_V3_ACCENT_COLOR);
- assertTrue("> 10 pixels should be #1a73e8. Found " + accentPixelCount,
- accentPixelCount > 10);
- }
-
- private Button createButton(@StyleRes int theme)
- throws InstantiationException, IllegalAccessException {
- final ViewGroup parent = new LinearLayout(DrawingTestHelper.createCanvasActivity(theme));
- TestButtonItem item = new TestButtonItem();
- item.setTheme(R.style.SuwButtonItem_Colored);
- item.setText("foobar");
-
- return item.createButton(parent);
- }
-
- private int countPixelsWithColor(int[] pixels, int color) {
- int count = 0;
- for (int pixel : pixels) {
- if (pixel == color) {
- count++;
- }
- }
- return count;
+ private static final int GLIF_ACCENT_COLOR = 0xff4285f4;
+ private static final int GLIF_V3_ACCENT_COLOR = 0xff1a73e8;
+
+ // These tests need to be run on UI thread because button uses ValueAnimator
+ @Rule public UiThreadTestRule mUiThreadTestRule = new UiThreadTestRule();
+
+ @Test
+ @UiThreadTest
+ public void drawButton_glif_shouldHaveAccentColoredButton()
+ throws InstantiationException, IllegalAccessException {
+ Button button = createButton(R.style.SuwThemeGlif_Light);
+
+ DrawingTestHelper drawingTestHelper = new DrawingTestHelper(50, 50);
+ drawingTestHelper.drawView(button);
+
+ int accentPixelCount = countPixelsWithColor(drawingTestHelper.getPixels(), GLIF_ACCENT_COLOR);
+ assertTrue("> 10 pixels should be #4285f4. Found " + accentPixelCount, accentPixelCount > 10);
+ }
+
+ @Test
+ @UiThreadTest
+ public void drawButton_glifV3_shouldHaveAccentColoredButton()
+ throws InstantiationException, IllegalAccessException {
+ Button button = createButton(R.style.SuwThemeGlifV3_Light);
+
+ DrawingTestHelper drawingTestHelper = new DrawingTestHelper(50, 50);
+ drawingTestHelper.drawView(button);
+
+ int accentPixelCount =
+ countPixelsWithColor(drawingTestHelper.getPixels(), GLIF_V3_ACCENT_COLOR);
+ assertTrue("> 10 pixels should be #1a73e8. Found " + accentPixelCount, accentPixelCount > 10);
+ }
+
+ private Button createButton(@StyleRes int theme)
+ throws InstantiationException, IllegalAccessException {
+ final ViewGroup parent = new LinearLayout(DrawingTestHelper.createCanvasActivity(theme));
+ TestButtonItem item = new TestButtonItem();
+ item.setTheme(R.style.SuwButtonItem_Colored);
+ item.setText("foobar");
+
+ return item.createButton(parent);
+ }
+
+ private int countPixelsWithColor(int[] pixels, int color) {
+ int count = 0;
+ for (int pixel : pixels) {
+ if (pixel == color) {
+ count++;
+ }
}
+ return count;
+ }
- private static class TestButtonItem extends ButtonItem {
+ private static class TestButtonItem extends ButtonItem {
- @Override
- public Button createButton(ViewGroup parent) {
- // Make this method public for testing
- return super.createButton(parent);
- }
+ @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/util/DrawingTestActivity.java b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java
index d3518f4..80e23e9 100644
--- 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
@@ -26,5 +26,4 @@ import androidx.appcompat.app.AppCompatActivity;
*
* @see DrawingTestHelper
*/
-public class DrawingTestActivity extends AppCompatActivity {
-}
+public class DrawingTestActivity extends AppCompatActivity {}
diff --git a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java
index 7b4ad4d..da5e16c 100644
--- a/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java
+++ b/library/gingerbread/test/instrumentation/src/com/android/setupwizardlib/util/LinkAccessibilityHelperTest.java
@@ -25,342 +25,334 @@ import static org.mockito.Mockito.verify;
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 androidx.core.view.AccessibilityDelegateCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
+import androidx.customview.widget.ExploreByTouchHelper;
import android.text.SpannableStringBuilder;
import android.util.DisplayMetrics;
import android.util.TypedValue;
-import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import android.widget.TextView;
-
import androidx.core.text.BidiFormatter;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
-import androidx.customview.widget.ExploreByTouchHelper;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.span.LinkSpan;
import com.android.setupwizardlib.util.LinkAccessibilityHelper.PreOLinkAccessibilityHelper;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class LinkAccessibilityHelperTest {
- private static final LinkSpan LINK_SPAN = new LinkSpan("foobar");
-
- private TextView mTextView;
- private TestPreOLinkAccessibilityHelper 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. "
+ private static final LinkSpan LINK_SPAN = new LinkSpan("foobar");
+
+ private TextView mTextView;
+ private TestPreOLinkAccessibilityHelper 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();
+ 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();
+ }
+
+ @Test
+ public void testMethodDelegation() {
+ initTextView();
+ AccessibilityDelegateCompat delegate = mock(AccessibilityDelegateCompat.class);
+ LinkAccessibilityHelper helper = new LinkAccessibilityHelper(delegate);
+
+ AccessibilityEvent accessibilityEvent =
+ AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_CLICKED);
+
+ helper.sendAccessibilityEvent(mTextView, AccessibilityEvent.TYPE_VIEW_CLICKED);
+ verify(delegate)
+ .sendAccessibilityEvent(same(mTextView), eq(AccessibilityEvent.TYPE_VIEW_CLICKED));
+
+ helper.sendAccessibilityEventUnchecked(mTextView, accessibilityEvent);
+ verify(delegate).sendAccessibilityEventUnchecked(same(mTextView), same(accessibilityEvent));
+
+ helper.performAccessibilityAction(
+ mTextView, AccessibilityActionCompat.ACTION_CLICK.getId(), Bundle.EMPTY);
+ verify(delegate)
+ .performAccessibilityAction(
+ same(mTextView), eq(AccessibilityActionCompat.ACTION_CLICK.getId()), eq(Bundle.EMPTY));
+
+ helper.dispatchPopulateAccessibilityEvent(mTextView, accessibilityEvent);
+ verify(delegate).dispatchPopulateAccessibilityEvent(same(mTextView), same(accessibilityEvent));
+
+ helper.getAccessibilityNodeProvider(mTextView);
+ verify(delegate).getAccessibilityNodeProvider(same(mTextView));
+
+ helper.onInitializeAccessibilityEvent(mTextView, accessibilityEvent);
+ verify(delegate).onInitializeAccessibilityEvent(same(mTextView), eq(accessibilityEvent));
+
+ AccessibilityNodeInfoCompat accessibilityNodeInfo = AccessibilityNodeInfoCompat.obtain();
+ helper.onInitializeAccessibilityNodeInfo(mTextView, accessibilityNodeInfo);
+ verify(delegate)
+ .onInitializeAccessibilityNodeInfo(same(mTextView), same(accessibilityNodeInfo));
+
+ helper.onPopulateAccessibilityEvent(mTextView, accessibilityEvent);
+ verify(delegate).onPopulateAccessibilityEvent(same(mTextView), same(accessibilityEvent));
+
+ FrameLayout parent = new FrameLayout(InstrumentationRegistry.getTargetContext());
+ helper.onRequestSendAccessibilityEvent(parent, mTextView, accessibilityEvent);
+ verify(delegate)
+ .onRequestSendAccessibilityEvent(same(parent), same(mTextView), same(accessibilityEvent));
+ }
+
+ 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 TestPreOLinkAccessibilityHelper(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);
+ }
- @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();
- }
+ public static class TestPreOLinkAccessibilityHelper extends PreOLinkAccessibilityHelper {
- @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();
+ TestPreOLinkAccessibilityHelper(TextView view) {
+ super(view);
}
- @Test
- public void testMethodDelegation() {
- initTextView();
- ExploreByTouchHelper delegate = mock(TestPreOLinkAccessibilityHelper.class);
- LinkAccessibilityHelper helper = new LinkAccessibilityHelper(delegate);
-
- AccessibilityEvent accessibilityEvent =
- AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_CLICKED);
-
- helper.sendAccessibilityEvent(mTextView, AccessibilityEvent.TYPE_VIEW_CLICKED);
- verify(delegate).sendAccessibilityEvent(
- same(mTextView),
- eq(AccessibilityEvent.TYPE_VIEW_CLICKED));
-
- helper.sendAccessibilityEventUnchecked(mTextView, accessibilityEvent);
- verify(delegate).sendAccessibilityEventUnchecked(same(mTextView), same(accessibilityEvent));
-
- helper.performAccessibilityAction(
- mTextView,
- AccessibilityActionCompat.ACTION_CLICK.getId(),
- Bundle.EMPTY);
- verify(delegate).performAccessibilityAction(
- same(mTextView),
- eq(AccessibilityActionCompat.ACTION_CLICK.getId()),
- eq(Bundle.EMPTY));
-
- helper.dispatchPopulateAccessibilityEvent(
- mTextView,
- accessibilityEvent);
- verify(delegate).dispatchPopulateAccessibilityEvent(
- same(mTextView),
- same(accessibilityEvent));
-
- MotionEvent motionEvent = MotionEvent.obtain(0, 0, 0, 0, 0, 0);
- helper.dispatchHoverEvent(motionEvent);
- verify(delegate).dispatchHoverEvent(eq(motionEvent));
-
- helper.getAccessibilityNodeProvider(mTextView);
- verify(delegate).getAccessibilityNodeProvider(same(mTextView));
-
- helper.onInitializeAccessibilityEvent(mTextView, accessibilityEvent);
- verify(delegate).onInitializeAccessibilityEvent(
- same(mTextView),
- eq(accessibilityEvent));
-
- AccessibilityNodeInfoCompat accessibilityNodeInfo = AccessibilityNodeInfoCompat.obtain();
- helper.onInitializeAccessibilityNodeInfo(mTextView, accessibilityNodeInfo);
- verify(delegate).onInitializeAccessibilityNodeInfo(
- same(mTextView),
- same(accessibilityNodeInfo));
-
- helper.onPopulateAccessibilityEvent(mTextView, accessibilityEvent);
- verify(delegate).onPopulateAccessibilityEvent(
- same(mTextView),
- same(accessibilityEvent));
-
- FrameLayout parent = new FrameLayout(InstrumentationRegistry.getTargetContext());
- helper.onRequestSendAccessibilityEvent(parent, mTextView, accessibilityEvent);
- verify(delegate).onRequestSendAccessibilityEvent(
- same(parent),
- same(mTextView),
- same(accessibilityEvent));
+ @Override
+ public int getVirtualViewAt(float x, float y) {
+ return super.getVirtualViewAt(x, y);
}
- private void initTextView() {
- SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
- ssb.setSpan(LINK_SPAN, 1, 2, 0 /* flags */);
- initTextView(ssb);
+ @Override
+ public void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+ super.getVisibleVirtualViews(virtualViewIds);
}
- 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 TestPreOLinkAccessibilityHelper(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));
+ @Override
+ public void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
+ super.onPopulateEventForVirtualView(virtualViewId, event);
}
- private int dp2Px(float dp) {
- if (mDisplayMetrics == null) {
- mDisplayMetrics =
- InstrumentationRegistry.getContext().getResources().getDisplayMetrics();
- }
- return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDisplayMetrics);
+ @Override
+ public void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat info) {
+ super.onPopulateNodeForVirtualView(virtualViewId, info);
}
- public static class TestPreOLinkAccessibilityHelper extends PreOLinkAccessibilityHelper {
-
- TestPreOLinkAccessibilityHelper(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);
- }
+ @Override
+ public boolean onPerformActionForVirtualView(int virtualViewId, int action, Bundle arguments) {
+ return super.onPerformActionForVirtualView(virtualViewId, action, arguments);
}
+ }
}
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
index 6192061..c43b4ab 100644
--- a/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/ExpandableSwitchItemTest.java
+++ b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/ExpandableSwitchItemTest.java
@@ -17,7 +17,6 @@
package com.android.setupwizardlib.items;
import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -27,133 +26,139 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-
import com.android.setupwizardlib.R;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
import com.android.setupwizardlib.view.CheckableLinearLayout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
+@RunWith(RobolectricTestRunner.class)
+@Config(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());
-
- assertFalse("Expandable switch item itself should not be focusable", view.isFocusable());
-
- View switchContent = view.findViewById(R.id.suw_items_expandable_switch_content);
- assertThat(switchContent).isInstanceOf(CheckableLinearLayout.class);
- assertThat(switchContent.isFocusable())
- .named("expandable content focusable")
- .isTrue();
- }
-
- @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(titleView.getDrawableState()).asList().named("Drawable state")
- .doesNotContain(android.R.attr.state_checked);
-
- mItem.setExpanded(true);
- mItem.onBindView(view);
- assertThat(titleView.getDrawableState()).asList().named("Drawable state")
- .contains(android.R.attr.state_checked);
-
- mItem.setExpanded(false);
- mItem.onBindView(view);
- assertThat(titleView.getDrawableState()).asList().named("Drawable state")
- .doesNotContain(android.R.attr.state_checked);
- }
-
- private ViewGroup createLayout() {
- ViewGroup root =
- (ViewGroup) LayoutInflater.from(application)
- .inflate(R.layout.suw_items_expandable_switch, null);
- mSummaryView = root.findViewById(R.id.suw_items_summary);
-
- return root;
- }
+ 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());
+
+ assertFalse("Expandable switch item itself should not be focusable", view.isFocusable());
+
+ View switchContent = view.findViewById(R.id.suw_items_expandable_switch_content);
+ assertThat(switchContent).isInstanceOf(CheckableLinearLayout.class);
+ assertThat(switchContent.isFocusable()).named("expandable content focusable").isTrue();
+ }
+
+ @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(titleView.getDrawableState())
+ .asList()
+ .named("Drawable state")
+ .doesNotContain(android.R.attr.state_checked);
+
+ mItem.setExpanded(true);
+ mItem.onBindView(view);
+ assertThat(titleView.getDrawableState())
+ .asList()
+ .named("Drawable state")
+ .contains(android.R.attr.state_checked);
+
+ mItem.setExpanded(false);
+ mItem.onBindView(view);
+ assertThat(titleView.getDrawableState())
+ .asList()
+ .named("Drawable state")
+ .doesNotContain(android.R.attr.state_checked);
+ }
+
+ private ViewGroup createLayout() {
+ ViewGroup root =
+ (ViewGroup)
+ LayoutInflater.from(application).inflate(R.layout.suw_items_expandable_switch, null);
+ mSummaryView = root.findViewById(R.id.suw_items_summary);
+
+ 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
index 05d6e5b..422d979 100644
--- a/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java
+++ b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/items/SwitchItemTest.java
@@ -17,7 +17,6 @@
package com.android.setupwizardlib.items;
import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -26,219 +25,232 @@ import static org.robolectric.RuntimeEnvironment.application;
import android.annotation.TargetApi;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
+import androidx.appcompat.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.LinearLayout;
import android.widget.TextView;
-
-import androidx.appcompat.widget.SwitchCompat;
-
import com.android.setupwizardlib.R;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
public class SwitchItemTest {
- private SwitchCompat mSwitch;
+ private SwitchCompat mSwitch;
- @Test
- public void testLayout() {
- Assume.assumeTrue(VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP);
- SwitchItem item = new SwitchItem();
- LayoutInflater inflater = LayoutInflater.from(application);
- ViewGroup layout = (ViewGroup) inflater.inflate(item.getDefaultLayoutResource(), null);
- assertThat(layout.getClipToPadding()).isFalse();
- }
+ @Test
+ public void defaultLayout_baselineAligned_shouldBeFalse() {
+ Assume.assumeTrue(VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP);
+ LayoutInflater inflater = LayoutInflater.from(application);
+ SwitchItem item = new SwitchItem();
+ LinearLayout layout = (LinearLayout) inflater.inflate(item.getDefaultLayoutResource(), null);
+ assertThat(layout.isBaselineAligned()).isFalse();
+ }
+
+ @Test
+ public void verboseLayout_clipPadding_shouldBeFalse() {
+ Assume.assumeTrue(VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP);
+ LayoutInflater inflater = LayoutInflater.from(application);
+ SwitchItem item =
+ new SwitchItem(
+ application,
+ Robolectric.buildAttributeSet()
+ .addAttribute(android.R.attr.layout, "@layout/suw_items_switch_verbose")
+ .build());
+ ViewGroup layout = (ViewGroup) inflater.inflate(item.getLayoutResource(), null);
+ assertThat(layout.getClipToPadding()).isFalse();
+ }
- @Test
- public void testChecked() {
- SwitchItem item = new SwitchItem();
- item.setTitle("TestTitle");
- item.setSummary("TestSummary");
- View view = createLayout();
+ @Test
+ public void testChecked() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
- item.setChecked(true);
+ item.setChecked(true);
- item.onBindView(view);
+ item.onBindView(view);
- assertTrue("Switch should be checked", mSwitch.isChecked());
- }
+ assertTrue("Switch should be checked", mSwitch.isChecked());
+ }
- @Test
- public void testNotChecked() {
- SwitchItem item = new SwitchItem();
- item.setTitle("TestTitle");
- item.setSummary("TestSummary");
- View view = createLayout();
+ @Test
+ public void testNotChecked() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
- item.setChecked(false);
+ item.setChecked(false);
- item.onBindView(view);
+ item.onBindView(view);
- assertFalse("Switch should be unchecked", mSwitch.isChecked());
- }
+ assertFalse("Switch should be unchecked", mSwitch.isChecked());
+ }
- @Test
- public void testListener() {
- SwitchItem item = new SwitchItem();
- item.setTitle("TestTitle");
- item.setSummary("TestSummary");
- View view = createLayout();
+ @Test
+ public void testListener() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
- item.setChecked(true);
+ item.setChecked(true);
- final TestOnCheckedChangeListener listener = new TestOnCheckedChangeListener();
- item.setOnCheckedChangeListener(listener);
+ final TestOnCheckedChangeListener listener = new TestOnCheckedChangeListener();
+ item.setOnCheckedChangeListener(listener);
- item.onBindView(view);
+ item.onBindView(view);
- assertTrue("Switch should be checked", mSwitch.isChecked());
- mSwitch.setChecked(false);
+ 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);
+ assertTrue("Listener should be called", listener.mCalled);
+ assertFalse("Listener should not be checked", listener.mChecked);
- mSwitch.setChecked(true);
+ mSwitch.setChecked(true);
- assertTrue("Listener should be called", listener.mCalled);
- assertTrue("Listener should be checked", listener.mChecked);
- }
+ 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);
+ @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);
+ SwitchItem item2 = new SwitchItem();
+ item2.setTitle("TestTitle2");
+ item2.setSummary("TestSummary2");
+ item2.setChecked(true);
- View view = createLayout();
+ View view = createLayout();
- item1.onBindView(view);
- item2.onBindView(view);
+ item1.onBindView(view);
+ item2.onBindView(view);
- // Switch should be bound to item2, and therefore checked
- assertTrue("Switch should be checked", mSwitch.isChecked());
+ // 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 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());
- }
+ // 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.
+ @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();
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
- item.setChecked(true);
+ item.setChecked(true);
- final TestOnCheckedChangeListener listener = new TestOnCheckedChangeListener();
- item.setOnCheckedChangeListener(listener);
+ final TestOnCheckedChangeListener listener = new TestOnCheckedChangeListener();
+ item.setOnCheckedChangeListener(listener);
- item.onBindView(view);
+ item.onBindView(view);
- assertTrue("Switch should be checked", mSwitch.isChecked());
- item.setChecked(false);
+ 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);
+ assertTrue("Listener should be called", listener.mCalled);
+ assertFalse("Listener should not be checked", listener.mChecked);
- item.setChecked(true);
+ item.setChecked(true);
- assertTrue("Listener should be called", listener.mCalled);
- assertTrue("Listener should be checked", listener.mChecked);
- }
+ 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();
+ @Test
+ public void testToggle() {
+ SwitchItem item = new SwitchItem();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ View view = createLayout();
- item.setChecked(true);
- item.onBindView(view);
+ item.setChecked(true);
+ item.onBindView(view);
- assertTrue("Switch should be checked", mSwitch.isChecked());
+ assertTrue("Switch should be checked", mSwitch.isChecked());
- item.toggle(view);
+ item.toggle(view);
- assertFalse("Switch should be unchecked", mSwitch.isChecked());
- }
+ 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");
+ @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);
+ 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());
- }
+ 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);
+ private ViewGroup createLayout() {
+ ViewGroup root = new FrameLayout(application);
- TextView titleView = new TextView(application);
- titleView.setId(R.id.suw_items_title);
- root.addView(titleView);
+ 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);
+ 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);
+ 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);
+ 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);
+ mSwitch = new SwitchCompat(application);
+ mSwitch.setId(R.id.suw_items_switch);
+ root.addView(mSwitch);
- return root;
- }
+ return root;
+ }
- private static class TestOnCheckedChangeListener implements SwitchItem.OnCheckedChangeListener {
+ private static class TestOnCheckedChangeListener implements SwitchItem.OnCheckedChangeListener {
- boolean mCalled = false;
- boolean mChecked = false;
+ boolean mCalled = false;
+ boolean mChecked = false;
- @Override
- public void onCheckedChange(SwitchItem item, boolean isChecked) {
- mCalled = true;
- mChecked = isChecked;
- }
+ @Override
+ public void onCheckedChange(SwitchItem item, boolean isChecked) {
+ mCalled = true;
+ mChecked = isChecked;
}
+ }
}
diff --git a/library/gingerbread/test/robotest/src/com/android/setupwizardlib/util/DimensionConsistencyTest.java b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/util/DimensionConsistencyTest.java
index 7a08235..1f76d35 100644
--- a/library/gingerbread/test/robotest/src/com/android/setupwizardlib/util/DimensionConsistencyTest.java
+++ b/library/gingerbread/test/robotest/src/com/android/setupwizardlib/util/DimensionConsistencyTest.java
@@ -24,45 +24,42 @@ import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
-
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.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
@Config(sdk = Config.ALL_SDKS)
public class DimensionConsistencyTest {
- // Visual height of the framework switch widget
- private static final int SWTICH_HEIGHT_DP = 26;
+ // Visual height of the framework switch widget
+ private static final int SWTICH_HEIGHT_DP = 26;
- private Context mContext;
+ private Context mContext;
- @Before
- public void setUp() {
- mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
- }
+ @Before
+ public void setUp() {
+ mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
+ }
- @Test
- public void testSwitchPaddingTop() {
- final Resources res = mContext.getResources();
+ @Test
+ public void testSwitchPaddingTop() {
+ final Resources res = mContext.getResources();
- assertEquals(
- "Switch and divider should be aligned at center vertically: "
- + "suw_switch_padding_top + SWITCH_HEIGHT / 2 = "
- + "suw_switch_divider_padding_top + suw_switch_divider_height / 2",
- res.getDimensionPixelSize(R.dimen.suw_switch_divider_padding_top)
- + (res.getDimensionPixelSize(R.dimen.suw_switch_divider_height) / 2),
- res.getDimensionPixelSize(R.dimen.suw_switch_padding_top)
- + (dp2Px(SWTICH_HEIGHT_DP) / 2));
- }
+ assertEquals(
+ "Switch and divider should be aligned at center vertically: "
+ + "suw_switch_padding_top + SWITCH_HEIGHT / 2 = "
+ + "suw_switch_divider_padding_top + suw_switch_divider_height / 2",
+ res.getDimensionPixelSize(R.dimen.suw_switch_divider_padding_top)
+ + (res.getDimensionPixelSize(R.dimen.suw_switch_divider_height) / 2),
+ res.getDimensionPixelSize(R.dimen.suw_switch_padding_top) + (dp2Px(SWTICH_HEIGHT_DP) / 2));
+ }
- private int dp2Px(float dp) {
- DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
- return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics);
- }
+ private int dp2Px(float dp) {
+ DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics);
+ }
}
diff --git a/library/grandfathered_lint_checks.txt b/library/grandfathered_lint_checks.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/library/grandfathered_lint_checks.txt
diff --git a/library/main/res/color-v23/suw_flat_button_highlight.xml b/library/main/res/color-v23/suw_flat_button_highlight.xml
index c5be14f..cdb1305 100644
--- a/library/main/res/color-v23/suw_flat_button_highlight.xml
+++ b/library/main/res/color-v23/suw_flat_button_highlight.xml
@@ -17,5 +17,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?android:attr/colorAccent"
- android:alpha="0.24" />
+ android:alpha="?attr/suwButtonHighlightAlpha" />
</selector>
diff --git a/library/main/res/values-as/strings.xml b/library/main/res/values-as/strings.xml
new file mode 100644
index 0000000..be6e06b
--- /dev/null
+++ b/library/main/res/values-as/strings.xml
@@ -0,0 +1,23 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="suw_next_button_label" msgid="7269625133873553978">"পৰৱৰ্তী"</string>
+ <string name="suw_back_button_label" msgid="1460929053642711025">"উভতি যাওক"</string>
+ <string name="suw_more_button_label" msgid="7769076059705546563">"অধিক"</string>
+</resources>
diff --git a/library/main/res/values-hi/strings.xml b/library/main/res/values-hi/strings.xml
index 3fb41d3..ec2cd77 100644
--- a/library/main/res/values-hi/strings.xml
+++ b/library/main/res/values-hi/strings.xml
@@ -19,5 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="suw_next_button_label" msgid="7269625133873553978">"आगे बढ़ें"</string>
<string name="suw_back_button_label" msgid="1460929053642711025">"पीछे"</string>
- <string name="suw_more_button_label" msgid="7769076059705546563">"अधिक"</string>
+ <string name="suw_more_button_label" msgid="7769076059705546563">"ज़्यादा"</string>
</resources>
diff --git a/library/main/res/values-mr/strings.xml b/library/main/res/values-mr/strings.xml
index a529655..5c5b6c2 100644
--- a/library/main/res/values-mr/strings.xml
+++ b/library/main/res/values-mr/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="suw_next_button_label" msgid="7269625133873553978">"पुढील"</string>
+ <string name="suw_next_button_label" msgid="7269625133873553978">"पुढे जा"</string>
<string name="suw_back_button_label" msgid="1460929053642711025">"मागे"</string>
<string name="suw_more_button_label" msgid="7769076059705546563">"अधिक"</string>
</resources>
diff --git a/library/main/res/values-night/styles.xml b/library/main/res/values-night/styles.xml
new file mode 100644
index 0000000..912e149
--- /dev/null
+++ b/library/main/res/values-night/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <!-- DayNight themes -->
+ <style name="SuwThemeMaterial.DayNight" parent="SuwThemeMaterial" />
+ <style name="SuwThemeGlif.DayNight" parent="SuwThemeGlif" />
+ <style name="SuwThemeGlifV2.DayNight" parent="SuwThemeGlifV2" />
+ <style name="SuwThemeGlifV3.DayNight" parent="SuwThemeGlifV3" />
+
+</resources>
diff --git a/library/main/res/values-or/strings.xml b/library/main/res/values-or/strings.xml
new file mode 100644
index 0000000..c4d12ff
--- /dev/null
+++ b/library/main/res/values-or/strings.xml
@@ -0,0 +1,23 @@
+<?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:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="suw_next_button_label" msgid="7269625133873553978">"ପରବର୍ତ୍ତୀ"</string>
+ <string name="suw_back_button_label" msgid="1460929053642711025">"ପଛକୁ ଫେରନ୍ତୁ"</string>
+ <string name="suw_more_button_label" msgid="7769076059705546563">"ଅଧିକ"</string>
+</resources>
diff --git a/library/main/res/values-v21/styles.xml b/library/main/res/values-v21/styles.xml
index d2c27f6..fe71289 100644
--- a/library/main/res/values-v21/styles.xml
+++ b/library/main/res/values-v21/styles.xml
@@ -38,10 +38,6 @@
<!-- Button styles -->
- <style name="SuwGlifButton.Tertiary" parent="SuwGlifButton.BaseTertiary">
- <item name="android:fontFamily">sans-serif-medium</item>
- </style>
-
<style name="SuwBase.ProgressBarLarge" parent="@android:style/Widget.Material.ProgressBar.Large" />
<style name="SuwFourColorIndeterminateProgressBar" parent="SuwBase.ProgressBarLarge">
@@ -50,6 +46,8 @@
<item name="android:indeterminateDrawable">@drawable/suw_fourcolor_progress_bar</item>
<item name="android:indeterminateTint">@null</item>
<item name="android:indeterminateTintMode">@null</item>
+ <item name="android:paddingStart">@dimen/suw_glif_progress_bar_padding</item>
+ <item name="android:paddingEnd">@dimen/suw_glif_progress_bar_padding</item>
</style>
<!-- Items styles -->
diff --git a/library/main/res/values/attrs.xml b/library/main/res/values/attrs.xml
index b3fcfe9..86b27fa 100644
--- a/library/main/res/values/attrs.xml
+++ b/library/main/res/values/attrs.xml
@@ -21,6 +21,7 @@
<attr name="suwLayoutTheme" format="reference" />
<attr name="suwMarginSides" format="dimension|reference" />
<attr name="suwEditTextBackgroundColor" format="color" />
+ <attr name="suwButtonHighlightAlpha" format="float" />
<!-- Subset of values in "gravity" in frameworks/base/core/res/res/values/attrs.xml. Only
horizontal values are listed here as the header does not support vertical gravity. -->
diff --git a/library/main/res/values/dimens.xml b/library/main/res/values/dimens.xml
index 1a8b516..63980ab 100644
--- a/library/main/res/values/dimens.xml
+++ b/library/main/res/values/dimens.xml
@@ -31,7 +31,7 @@
<dimen name="suw_glif_footer_padding_vertical">8dp</dimen>
<dimen name="suw_glif_footer_min_height">72dp</dimen>
<dimen name="suw_glif_margin_sides">24dp</dimen>
- <dimen name="suw_glif_margin_top">48dp</dimen>
+ <dimen name="suw_glif_margin_top">56dp</dimen>
<dimen name="suw_glif_v3_button_corner_radius">4dp</dimen>
@@ -98,7 +98,7 @@
<!-- This is the extra spacing required to make the leading exactly 32sp -->
<dimen name="suw_header_title_line_spacing_extra">3.67sp</dimen>
- <dimen name="suw_glif_header_title_margin_top">15dp</dimen>
+ <dimen name="suw_glif_header_title_margin_top">16dp</dimen>
<dimen name="suw_glif_header_title_margin_bottom">2dp</dimen>
<dimen name="suw_glif_icon_max_height">32dp</dimen>
@@ -139,6 +139,7 @@
<!-- The margin to compensate for the padding built-in to the widget itself -->
<dimen name="suw_progress_bar_margin_vertical">-7dp</dimen>
<dimen name="suw_glif_progress_bar_margin_vertical">7dp</dimen>
+ <dimen name="suw_glif_progress_bar_padding">40dp</dimen>
<!-- Edit Text dimensions -->
<dimen name="suw_edit_text_min_height">56dp</dimen>
diff --git a/library/main/res/values/styles.xml b/library/main/res/values/styles.xml
index fa2a080..34a917f 100644
--- a/library/main/res/values/styles.xml
+++ b/library/main/res/values/styles.xml
@@ -58,6 +58,12 @@
<item name="android:activityCloseExitAnimation">@anim/suw_slide_back_out</item>
</style>
+ <!-- DayNight themes -->
+ <style name="SuwThemeMaterial.DayNight" parent="SuwThemeMaterial.Light" />
+ <style name="SuwThemeGlif.DayNight" parent="SuwThemeGlif.Light" />
+ <style name="SuwThemeGlifV2.DayNight" parent="SuwThemeGlifV2.Light" />
+ <style name="SuwThemeGlifV3.DayNight" parent="SuwThemeGlifV3.Light" />
+
<!-- Content styles -->
<!-- Ignore UnusedResources: Used by clients -->
@@ -166,7 +172,7 @@
<!-- Before Honeycomb, layout_gravity is needed for FrameLayout to apply the margins -->
<item name="android:layout_gravity">top</item>
<item name="android:ellipsize">end</item>
- <item name="android:maxLines">2</item>
+ <item name="android:maxLines">3</item>
<item name="android:textSize">@dimen/suw_header_title_size</item>
</style>
@@ -204,11 +210,6 @@
<item name="android:textAllCaps" tools:targetApi="ice_cream_sandwich">false</item>
</style>
- <!-- Ignore UnusedResources: used by clients -->
- <style name="SuwGlifButton.Tertiary"
- parent="SuwGlifButton.BaseTertiary"
- tools:ignore="UnusedResources" />
-
<!-- The start and end paddings are asymmetric because start buttons are borderless buttons
which aligns the text label. -->
<style name="SuwGlifButtonBar">
diff --git a/library/main/src/com/android/setupwizardlib/GlifLayout.java b/library/main/src/com/android/setupwizardlib/GlifLayout.java
index 9b30c2f..20fb6b6 100644
--- a/library/main/src/com/android/setupwizardlib/GlifLayout.java
+++ b/library/main/src/com/android/setupwizardlib/GlifLayout.java
@@ -24,6 +24,9 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Build.VERSION_CODES;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -32,11 +35,6 @@ import android.view.ViewStub;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
-
-import androidx.annotation.LayoutRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
import com.android.setupwizardlib.template.ButtonFooterMixin;
import com.android.setupwizardlib.template.ColoredHeaderMixin;
import com.android.setupwizardlib.template.HeaderMixin;
@@ -50,6 +48,7 @@ import com.android.setupwizardlib.view.StatusBarBackgroundLayout;
* Layout for the GLIF theme used in Setup Wizard for N.
*
* <p>Example usage:
+ *
* <pre>{@code
* &lt;com.android.setupwizardlib.GlifLayout
* xmlns:android="http://schemas.android.com/apk/res/android"
@@ -66,259 +65,254 @@ import com.android.setupwizardlib.view.StatusBarBackgroundLayout;
*/
public class GlifLayout extends TemplateLayout {
- private static final String TAG = "GlifLayout";
-
- private ColorStateList mPrimaryColor;
-
- private boolean mBackgroundPatterned = true;
-
- /**
- * The color of the background. If null, the color will inherit from mPrimaryColor.
- */
- @Nullable
- private ColorStateList mBackgroundBaseColor;
-
- private boolean mLayoutFullscreen = true;
-
- public GlifLayout(Context context) {
- this(context, 0, 0);
- }
-
- public GlifLayout(Context context, int template) {
- this(context, template, 0);
- }
-
- public GlifLayout(Context context, int template, int containerId) {
- super(context, template, containerId);
- init(null, R.attr.suwLayoutTheme);
- }
+ private static final String TAG = "GlifLayout";
- public GlifLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs, R.attr.suwLayoutTheme);
- }
+ private ColorStateList primaryColor;
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public GlifLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(attrs, defStyleAttr);
- }
+ private boolean backgroundPatterned = true;
- // All the constructors delegate to this init method. The 3-argument constructor is not
- // available in LinearLayout before v11, so call super with the exact same arguments.
- private void init(AttributeSet attrs, int defStyleAttr) {
- registerMixin(HeaderMixin.class, new ColoredHeaderMixin(this, attrs, defStyleAttr));
- registerMixin(IconMixin.class, new IconMixin(this, attrs, defStyleAttr));
- registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
- registerMixin(ButtonFooterMixin.class, new ButtonFooterMixin(this));
- final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this);
- registerMixin(RequireScrollMixin.class, requireScrollMixin);
-
- final ScrollView scrollView = getScrollView();
- if (scrollView != null) {
- requireScrollMixin.setScrollHandlingDelegate(
- new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView));
- }
-
- TypedArray a = getContext().obtainStyledAttributes(attrs,
- R.styleable.SuwGlifLayout, defStyleAttr, 0);
-
- ColorStateList primaryColor =
- a.getColorStateList(R.styleable.SuwGlifLayout_suwColorPrimary);
- if (primaryColor != null) {
- setPrimaryColor(primaryColor);
- }
-
- ColorStateList backgroundColor =
- a.getColorStateList(R.styleable.SuwGlifLayout_suwBackgroundBaseColor);
- setBackgroundBaseColor(backgroundColor);
-
- boolean backgroundPatterned =
- a.getBoolean(R.styleable.SuwGlifLayout_suwBackgroundPatterned, true);
- setBackgroundPatterned(backgroundPatterned);
-
- final int footer = a.getResourceId(R.styleable.SuwGlifLayout_suwFooter, 0);
- if (footer != 0) {
- inflateFooter(footer);
- }
-
- final int stickyHeader = a.getResourceId(R.styleable.SuwGlifLayout_suwStickyHeader, 0);
- if (stickyHeader != 0) {
- inflateStickyHeader(stickyHeader);
- }
-
- mLayoutFullscreen = a.getBoolean(R.styleable.SuwGlifLayout_suwLayoutFullscreen, true);
-
- a.recycle();
-
- if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && mLayoutFullscreen) {
- setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- }
- }
+ /** The color of the background. If null, the color will inherit from primaryColor. */
+ @Nullable private ColorStateList backgroundBaseColor;
- @Override
- protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) {
- if (template == 0) {
- template = R.layout.suw_glif_template;
- }
- return inflateTemplate(inflater, R.style.SuwThemeGlif_Light, template);
- }
+ private boolean layoutFullscreen = true;
- @Override
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- containerId = R.id.suw_layout_content;
- }
- return super.findContainer(containerId);
- }
+ public GlifLayout(Context context) {
+ this(context, 0, 0);
+ }
- /**
- * Sets the footer of the layout, which is at the bottom of the content area outside the
- * scrolling container. The footer can only be inflated once per instance of this layout.
- *
- * @param footer The layout to be inflated as footer.
- * @return The root of the inflated footer view.
- */
- public View inflateFooter(@LayoutRes int footer) {
- ViewStub footerStub = findManagedViewById(R.id.suw_layout_footer);
- footerStub.setLayoutResource(footer);
- return footerStub.inflate();
- }
+ public GlifLayout(Context context, int template) {
+ this(context, template, 0);
+ }
- /**
- * Sets the sticky header (i.e. header that doesn't scroll) of the layout, which is at the top
- * of the content area outside of the scrolling container. The header can only be inflated once
- * per instance of this layout.
- *
- * @param header The layout to be inflated as the header.
- * @return The root of the inflated header view.
- */
- public View inflateStickyHeader(@LayoutRes int header) {
- ViewStub stickyHeaderStub = findManagedViewById(R.id.suw_layout_sticky_header);
- stickyHeaderStub.setLayoutResource(header);
- return stickyHeaderStub.inflate();
- }
+ public GlifLayout(Context context, int template, int containerId) {
+ super(context, template, containerId);
+ init(null, R.attr.suwLayoutTheme);
+ }
- public ScrollView getScrollView() {
- final View view = findManagedViewById(R.id.suw_scroll_view);
- return view instanceof ScrollView ? (ScrollView) view : null;
- }
+ public GlifLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, R.attr.suwLayoutTheme);
+ }
- public TextView getHeaderTextView() {
- return getMixin(HeaderMixin.class).getTextView();
- }
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public GlifLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
- public void setHeaderText(int title) {
- getMixin(HeaderMixin.class).setText(title);
- }
+ // All the constructors delegate to this init method. The 3-argument constructor is not
+ // available in LinearLayout before v11, so call super with the exact same arguments.
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ registerMixin(HeaderMixin.class, new ColoredHeaderMixin(this, attrs, defStyleAttr));
+ registerMixin(IconMixin.class, new IconMixin(this, attrs, defStyleAttr));
+ registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
+ registerMixin(ButtonFooterMixin.class, new ButtonFooterMixin(this));
+ final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this);
+ registerMixin(RequireScrollMixin.class, requireScrollMixin);
- public void setHeaderText(CharSequence title) {
- getMixin(HeaderMixin.class).setText(title);
+ final ScrollView scrollView = getScrollView();
+ if (scrollView != null) {
+ requireScrollMixin.setScrollHandlingDelegate(
+ new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView));
}
- public CharSequence getHeaderText() {
- return getMixin(HeaderMixin.class).getText();
- }
+ TypedArray a =
+ getContext().obtainStyledAttributes(attrs, R.styleable.SuwGlifLayout, defStyleAttr, 0);
- public void setHeaderColor(ColorStateList color) {
- final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
- mixin.setColor(color);
+ ColorStateList primaryColor = a.getColorStateList(R.styleable.SuwGlifLayout_suwColorPrimary);
+ if (primaryColor != null) {
+ setPrimaryColor(primaryColor);
}
- public ColorStateList getHeaderColor() {
- final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
- return mixin.getColor();
- }
+ ColorStateList backgroundColor =
+ a.getColorStateList(R.styleable.SuwGlifLayout_suwBackgroundBaseColor);
+ setBackgroundBaseColor(backgroundColor);
- public void setIcon(Drawable icon) {
- getMixin(IconMixin.class).setIcon(icon);
- }
+ boolean backgroundPatterned =
+ a.getBoolean(R.styleable.SuwGlifLayout_suwBackgroundPatterned, true);
+ setBackgroundPatterned(backgroundPatterned);
- public Drawable getIcon() {
- return getMixin(IconMixin.class).getIcon();
+ final int footer = a.getResourceId(R.styleable.SuwGlifLayout_suwFooter, 0);
+ if (footer != 0) {
+ inflateFooter(footer);
}
- /**
- * Sets the primary color of this layout, which will be used to determine the color of the
- * progress bar and the background pattern.
- */
- public void setPrimaryColor(@NonNull ColorStateList color) {
- mPrimaryColor = color;
- updateBackground();
- getMixin(ProgressBarMixin.class).setColor(color);
+ final int stickyHeader = a.getResourceId(R.styleable.SuwGlifLayout_suwStickyHeader, 0);
+ if (stickyHeader != 0) {
+ inflateStickyHeader(stickyHeader);
}
- public ColorStateList getPrimaryColor() {
- return mPrimaryColor;
- }
+ layoutFullscreen = a.getBoolean(R.styleable.SuwGlifLayout_suwLayoutFullscreen, true);
- /**
- * Sets the base color of the background view, which is the status bar for phones and the full-
- * screen background for tablets. If {@link #isBackgroundPatterned()} is true, the pattern will
- * be drawn with this color.
- *
- * @param color The color to use as the base color of the background. If {@code null},
- * {@link #getPrimaryColor()} will be used.
- */
- public void setBackgroundBaseColor(@Nullable ColorStateList color) {
- mBackgroundBaseColor = color;
- updateBackground();
- }
+ a.recycle();
- /**
- * @return The base color of the background. {@code null} indicates the background will be drawn
- * with {@link #getPrimaryColor()}.
- */
- @Nullable
- public ColorStateList getBackgroundBaseColor() {
- return mBackgroundBaseColor;
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && layoutFullscreen) {
+ setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
+ }
- /**
- * Sets whether the background should be {@link GlifPatternDrawable}. If {@code false}, the
- * background will be a solid color.
- */
- public void setBackgroundPatterned(boolean patterned) {
- mBackgroundPatterned = patterned;
- updateBackground();
+ @Override
+ protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) {
+ if (template == 0) {
+ template = R.layout.suw_glif_template;
}
+ return inflateTemplate(inflater, R.style.SuwThemeGlif_Light, template);
+ }
- /**
- * @return True if this view uses {@link GlifPatternDrawable} as background.
- */
- public boolean isBackgroundPatterned() {
- return mBackgroundPatterned;
+ @Override
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ containerId = R.id.suw_layout_content;
}
-
- private void updateBackground() {
- final View patternBg = findManagedViewById(R.id.suw_pattern_bg);
- if (patternBg != null) {
- int backgroundColor = 0;
- if (mBackgroundBaseColor != null) {
- backgroundColor = mBackgroundBaseColor.getDefaultColor();
- } else if (mPrimaryColor != null) {
- backgroundColor = mPrimaryColor.getDefaultColor();
- }
- Drawable background = mBackgroundPatterned
- ? new GlifPatternDrawable(backgroundColor)
- : new ColorDrawable(backgroundColor);
- if (patternBg instanceof StatusBarBackgroundLayout) {
- ((StatusBarBackgroundLayout) patternBg).setStatusBarBackground(background);
- } else {
- patternBg.setBackgroundDrawable(background);
- }
- }
+ return super.findContainer(containerId);
+ }
+
+ /**
+ * Sets the footer of the layout, which is at the bottom of the content area outside the scrolling
+ * container. The footer can only be inflated once per instance of this layout.
+ *
+ * @param footer The layout to be inflated as footer.
+ * @return The root of the inflated footer view.
+ */
+ public View inflateFooter(@LayoutRes int footer) {
+ ViewStub footerStub = findManagedViewById(R.id.suw_layout_footer);
+ footerStub.setLayoutResource(footer);
+ return footerStub.inflate();
+ }
+
+ /**
+ * Sets the sticky header (i.e. header that doesn't scroll) of the layout, which is at the top of
+ * the content area outside of the scrolling container. The header can only be inflated once per
+ * instance of this layout.
+ *
+ * @param header The layout to be inflated as the header.
+ * @return The root of the inflated header view.
+ */
+ public View inflateStickyHeader(@LayoutRes int header) {
+ ViewStub stickyHeaderStub = findManagedViewById(R.id.suw_layout_sticky_header);
+ stickyHeaderStub.setLayoutResource(header);
+ return stickyHeaderStub.inflate();
+ }
+
+ public ScrollView getScrollView() {
+ final View view = findManagedViewById(R.id.suw_scroll_view);
+ return view instanceof ScrollView ? (ScrollView) view : null;
+ }
+
+ public TextView getHeaderTextView() {
+ return getMixin(HeaderMixin.class).getTextView();
+ }
+
+ public void setHeaderText(int title) {
+ getMixin(HeaderMixin.class).setText(title);
+ }
+
+ public void setHeaderText(CharSequence title) {
+ getMixin(HeaderMixin.class).setText(title);
+ }
+
+ public CharSequence getHeaderText() {
+ return getMixin(HeaderMixin.class).getText();
+ }
+
+ public void setHeaderColor(ColorStateList color) {
+ final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
+ mixin.setColor(color);
+ }
+
+ public ColorStateList getHeaderColor() {
+ final ColoredHeaderMixin mixin = (ColoredHeaderMixin) getMixin(HeaderMixin.class);
+ return mixin.getColor();
+ }
+
+ public void setIcon(Drawable icon) {
+ getMixin(IconMixin.class).setIcon(icon);
+ }
+
+ public Drawable getIcon() {
+ return getMixin(IconMixin.class).getIcon();
+ }
+
+ /**
+ * Sets the primary color of this layout, which will be used to determine the color of the
+ * progress bar and the background pattern.
+ */
+ public void setPrimaryColor(@NonNull ColorStateList color) {
+ primaryColor = color;
+ updateBackground();
+ getMixin(ProgressBarMixin.class).setColor(color);
+ }
+
+ public ColorStateList getPrimaryColor() {
+ return primaryColor;
+ }
+
+ /**
+ * Sets the base color of the background view, which is the status bar for phones and the full-
+ * screen background for tablets. If {@link #isBackgroundPatterned()} is true, the pattern will be
+ * drawn with this color.
+ *
+ * @param color The color to use as the base color of the background. If {@code null}, {@link
+ * #getPrimaryColor()} will be used.
+ */
+ public void setBackgroundBaseColor(@Nullable ColorStateList color) {
+ backgroundBaseColor = color;
+ updateBackground();
+ }
+
+ /**
+ * @return The base color of the background. {@code null} indicates the background will be drawn
+ * with {@link #getPrimaryColor()}.
+ */
+ @Nullable
+ public ColorStateList getBackgroundBaseColor() {
+ return backgroundBaseColor;
+ }
+
+ /**
+ * Sets whether the background should be {@link GlifPatternDrawable}. If {@code false}, the
+ * background will be a solid color.
+ */
+ public void setBackgroundPatterned(boolean patterned) {
+ backgroundPatterned = patterned;
+ updateBackground();
+ }
+
+ /** @return True if this view uses {@link GlifPatternDrawable} as background. */
+ public boolean isBackgroundPatterned() {
+ return backgroundPatterned;
+ }
+
+ private void updateBackground() {
+ final View patternBg = findManagedViewById(R.id.suw_pattern_bg);
+ if (patternBg != null) {
+ int backgroundColor = 0;
+ if (backgroundBaseColor != null) {
+ backgroundColor = backgroundBaseColor.getDefaultColor();
+ } else if (primaryColor != null) {
+ backgroundColor = primaryColor.getDefaultColor();
+ }
+ Drawable background =
+ backgroundPatterned
+ ? new GlifPatternDrawable(backgroundColor)
+ : new ColorDrawable(backgroundColor);
+ if (patternBg instanceof StatusBarBackgroundLayout) {
+ ((StatusBarBackgroundLayout) patternBg).setStatusBarBackground(background);
+ } else {
+ patternBg.setBackgroundDrawable(background);
+ }
}
+ }
- public boolean isProgressBarShown() {
- return getMixin(ProgressBarMixin.class).isShown();
- }
+ public boolean isProgressBarShown() {
+ return getMixin(ProgressBarMixin.class).isShown();
+ }
- public void setProgressBarShown(boolean shown) {
- getMixin(ProgressBarMixin.class).setShown(shown);
- }
+ public void setProgressBarShown(boolean shown) {
+ getMixin(ProgressBarMixin.class).setShown(shown);
+ }
- public ProgressBar peekProgressBar() {
- return getMixin(ProgressBarMixin.class).peekProgressBar();
- }
+ public ProgressBar peekProgressBar() {
+ return getMixin(ProgressBarMixin.class).peekProgressBar();
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/GlifListLayout.java b/library/main/src/com/android/setupwizardlib/GlifListLayout.java
index 8266e5f..c4f66fa 100644
--- a/library/main/src/com/android/setupwizardlib/GlifListLayout.java
+++ b/library/main/src/com/android/setupwizardlib/GlifListLayout.java
@@ -26,7 +26,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
-
import com.android.setupwizardlib.template.ListMixin;
import com.android.setupwizardlib.template.ListViewScrollHandlingDelegate;
import com.android.setupwizardlib.template.RequireScrollMixin;
@@ -37,130 +36,113 @@ import com.android.setupwizardlib.template.RequireScrollMixin;
*/
public class GlifListLayout extends GlifLayout {
- /* static section */
-
- private static final String TAG = "GlifListLayout";
-
- /* non-static section */
-
- private ListMixin mListMixin;
-
- public GlifListLayout(Context context) {
- this(context, 0, 0);
- }
-
- public GlifListLayout(Context context, int template) {
- this(context, template, 0);
- }
-
- public GlifListLayout(Context context, int template, int containerId) {
- super(context, template, containerId);
- init(context, null, 0);
- }
-
- public GlifListLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs, 0);
- }
-
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public GlifListLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs, defStyleAttr);
- }
-
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- mListMixin = new ListMixin(this, attrs, defStyleAttr);
- registerMixin(ListMixin.class, mListMixin);
-
- final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
- requireScrollMixin.setScrollHandlingDelegate(
- new ListViewScrollHandlingDelegate(requireScrollMixin, getListView()));
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- mListMixin.onLayout();
- }
-
- @Override
- protected View onInflateTemplate(LayoutInflater inflater, int template) {
- if (template == 0) {
- template = R.layout.suw_glif_list_template;
- }
- return super.onInflateTemplate(inflater, template);
- }
-
- @Override
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- containerId = android.R.id.list;
- }
- return super.findContainer(containerId);
- }
-
- public ListView getListView() {
- return mListMixin.getListView();
- }
-
- public void setAdapter(ListAdapter adapter) {
- mListMixin.setAdapter(adapter);
- }
-
- public ListAdapter getAdapter() {
- return mListMixin.getAdapter();
- }
-
- /**
- * @deprecated Use {@link #setDividerInsets(int, int)} instead.
- */
- @Deprecated
- public void setDividerInset(int inset) {
- mListMixin.setDividerInset(inset);
- }
-
- /**
- * Sets the start inset of the divider. This will use the default divider drawable set in the
- * theme and apply insets to it.
- *
- * @param start The number of pixels to inset on the "start" side of the list divider. Typically
- * this will be either {@code @dimen/suw_items_glif_icon_divider_inset} or
- * {@code @dimen/suw_items_glif_text_divider_inset}.
- * @param end The number of pixels to inset on the "end" side of the list divider.
- *
- * @see ListMixin#setDividerInsets(int, int)
- */
- public void setDividerInsets(int start, int end) {
- mListMixin.setDividerInsets(start, end);
- }
-
- /**
- * @deprecated Use {@link #getDividerInsetStart()} instead.
- */
- @Deprecated
- public int getDividerInset() {
- return mListMixin.getDividerInset();
- }
-
- /**
- * @see ListMixin#getDividerInsetStart()
- */
- public int getDividerInsetStart() {
- return mListMixin.getDividerInsetStart();
- }
-
- /**
- * @see ListMixin#getDividerInsetEnd()
- */
- public int getDividerInsetEnd() {
- return mListMixin.getDividerInsetEnd();
- }
-
- /**
- * @see ListMixin#getDivider()
- */
- public Drawable getDivider() {
- return mListMixin.getDivider();
- }
+ private ListMixin listMixin;
+
+ public GlifListLayout(Context context) {
+ this(context, 0, 0);
+ }
+
+ public GlifListLayout(Context context, int template) {
+ this(context, template, 0);
+ }
+
+ public GlifListLayout(Context context, int template, int containerId) {
+ super(context, template, containerId);
+ init(null, 0);
+ }
+
+ public GlifListLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public GlifListLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ listMixin = new ListMixin(this, attrs, defStyleAttr);
+ registerMixin(ListMixin.class, listMixin);
+
+ final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
+ requireScrollMixin.setScrollHandlingDelegate(
+ new ListViewScrollHandlingDelegate(requireScrollMixin, getListView()));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ listMixin.onLayout();
+ }
+
+ @Override
+ protected View onInflateTemplate(LayoutInflater inflater, int template) {
+ if (template == 0) {
+ template = R.layout.suw_glif_list_template;
+ }
+ return super.onInflateTemplate(inflater, template);
+ }
+
+ @Override
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ containerId = android.R.id.list;
+ }
+ return super.findContainer(containerId);
+ }
+
+ public ListView getListView() {
+ return listMixin.getListView();
+ }
+
+ public void setAdapter(ListAdapter adapter) {
+ listMixin.setAdapter(adapter);
+ }
+
+ public ListAdapter getAdapter() {
+ return listMixin.getAdapter();
+ }
+
+ /** @deprecated Use {@link #setDividerInsets(int, int)} instead. */
+ @Deprecated
+ public void setDividerInset(int inset) {
+ listMixin.setDividerInset(inset);
+ }
+
+ /**
+ * Sets the start inset of the divider. This will use the default divider drawable set in the
+ * theme and apply insets to it.
+ *
+ * @param start The number of pixels to inset on the "start" side of the list divider. Typically
+ * this will be either {@code @dimen/suw_items_glif_icon_divider_inset} or
+ * {@code @dimen/suw_items_glif_text_divider_inset}.
+ * @param end The number of pixels to inset on the "end" side of the list divider.
+ * @see ListMixin#setDividerInsets(int, int)
+ */
+ public void setDividerInsets(int start, int end) {
+ listMixin.setDividerInsets(start, end);
+ }
+
+ /** @deprecated Use {@link #getDividerInsetStart()} instead. */
+ @Deprecated
+ public int getDividerInset() {
+ return listMixin.getDividerInset();
+ }
+
+ /** @see ListMixin#getDividerInsetStart() */
+ public int getDividerInsetStart() {
+ return listMixin.getDividerInsetStart();
+ }
+
+ /** @see ListMixin#getDividerInsetEnd() */
+ public int getDividerInsetEnd() {
+ return listMixin.getDividerInsetEnd();
+ }
+
+ /** @see ListMixin#getDivider() */
+ public Drawable getDivider() {
+ return listMixin.getDivider();
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/GlifPatternDrawable.java b/library/main/src/com/android/setupwizardlib/GlifPatternDrawable.java
index caf92ac..f65f3ec 100644
--- a/library/main/src/com/android/setupwizardlib/GlifPatternDrawable.java
+++ b/library/main/src/com/android/setupwizardlib/GlifPatternDrawable.java
@@ -31,10 +31,8 @@ import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
-
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-
import java.lang.ref.SoftReference;
/**
@@ -42,263 +40,258 @@ import java.lang.ref.SoftReference;
* tablets in GLIF layout.
*/
public class GlifPatternDrawable extends Drawable {
- /*
- * This class essentially implements a simple SVG in Java code, with some special handling of
- * scaling when given different bounds.
- */
-
- /* static section */
-
- @SuppressLint("InlinedApi")
- private static final int[] ATTRS_PRIMARY_COLOR = new int[]{ android.R.attr.colorPrimary };
-
- private static final float VIEWBOX_HEIGHT = 768f;
- private static final float VIEWBOX_WIDTH = 1366f;
- // X coordinate of scale focus, as a fraction of of the width. (Range is 0 - 1)
- private static final float SCALE_FOCUS_X = .146f;
- // Y coordinate of scale focus, as a fraction of of the height. (Range is 0 - 1)
- private static final float SCALE_FOCUS_Y = .228f;
-
- // Alpha component of the color to be drawn, on top of the grayscale pattern. (Range is 0 - 1)
- private static final float COLOR_ALPHA = .8f;
- // Int version of COLOR_ALPHA. (Range is 0 - 255)
- private static final int COLOR_ALPHA_INT = (int) (COLOR_ALPHA * 255);
-
- // Cap the bitmap size, such that it won't hurt the performance too much
- // and it won't crash due to a very large scale.
- // The drawable will look blurry above this size.
- // This is a multiplier applied on top of the viewbox size.
- // Resulting max cache size = (1.5 x 1366, 1.5 x 768) = (2049, 1152)
- private static final float MAX_CACHED_BITMAP_SCALE = 1.5f;
-
- private static final int NUM_PATHS = 7;
-
- private static SoftReference<Bitmap> sBitmapCache;
- private static Path[] sPatternPaths;
- private static int[] sPatternLightness;
-
- public static GlifPatternDrawable getDefault(Context context) {
- int colorPrimary = 0;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- final TypedArray a = context.obtainStyledAttributes(ATTRS_PRIMARY_COLOR);
- colorPrimary = a.getColor(0, Color.BLACK);
- a.recycle();
- }
- return new GlifPatternDrawable(colorPrimary);
- }
-
- @VisibleForTesting
- public static void invalidatePattern() {
- sBitmapCache = null;
- }
-
- /* non-static section */
-
- private int mColor;
- private Paint mTempPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
- public GlifPatternDrawable(int color) {
- setColor(color);
+ /*
+ * This class essentially implements a simple SVG in Java code, with some special handling of
+ * scaling when given different bounds.
+ */
+
+ /* static section */
+
+ @SuppressLint("InlinedApi")
+ private static final int[] ATTRS_PRIMARY_COLOR = new int[] {android.R.attr.colorPrimary};
+
+ private static final float VIEWBOX_HEIGHT = 768f;
+ private static final float VIEWBOX_WIDTH = 1366f;
+ // X coordinate of scale focus, as a fraction of the width. (Range is 0 - 1)
+ private static final float SCALE_FOCUS_X = .146f;
+ // Y coordinate of scale focus, as a fraction of the height. (Range is 0 - 1)
+ private static final float SCALE_FOCUS_Y = .228f;
+
+ // Alpha component of the color to be drawn, on top of the grayscale pattern. (Range is 0 - 1)
+ private static final float COLOR_ALPHA = .8f;
+ // Int version of COLOR_ALPHA. (Range is 0 - 255)
+ private static final int COLOR_ALPHA_INT = (int) (COLOR_ALPHA * 255);
+
+ // Cap the bitmap size, such that it won't hurt the performance too much
+ // and it won't crash due to a very large scale.
+ // The drawable will look blurry above this size.
+ // This is a multiplier applied on top of the viewbox size.
+ // Resulting max cache size = (1.5 x 1366, 1.5 x 768) = (2049, 1152)
+ private static final float MAX_CACHED_BITMAP_SCALE = 1.5f;
+
+ private static final int NUM_PATHS = 7;
+
+ private static SoftReference<Bitmap> bitmapCache;
+ private static Path[] patternPaths;
+ private static int[] patternLightness;
+
+ public static GlifPatternDrawable getDefault(Context context) {
+ int colorPrimary = 0;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ final TypedArray a = context.obtainStyledAttributes(ATTRS_PRIMARY_COLOR);
+ colorPrimary = a.getColor(0, Color.BLACK);
+ a.recycle();
}
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- final Rect bounds = getBounds();
- int drawableWidth = bounds.width();
- int drawableHeight = bounds.height();
- Bitmap bitmap = null;
- if (sBitmapCache != null) {
- bitmap = sBitmapCache.get();
- }
- if (bitmap != null) {
- final int bitmapWidth = bitmap.getWidth();
- final int bitmapHeight = bitmap.getHeight();
- // Invalidate the cache if this drawable is bigger and we can still create a bigger
- // cache.
- if (drawableWidth > bitmapWidth
- && bitmapWidth < VIEWBOX_WIDTH * MAX_CACHED_BITMAP_SCALE) {
- bitmap = null;
- } else if (drawableHeight > bitmapHeight
- && bitmapHeight < VIEWBOX_HEIGHT * MAX_CACHED_BITMAP_SCALE) {
- bitmap = null;
- }
- }
-
- if (bitmap == null) {
- // Reset the paint so it can be used to draw the paths in renderOnCanvas
- mTempPaint.reset();
-
- bitmap = createBitmapCache(drawableWidth, drawableHeight);
- sBitmapCache = new SoftReference<>(bitmap);
-
- // Reset the paint to so it can be used to draw the bitmap
- mTempPaint.reset();
- }
-
- canvas.save();
- canvas.clipRect(bounds);
-
- scaleCanvasToBounds(canvas, bitmap, bounds);
- canvas.drawColor(Color.BLACK);
- mTempPaint.setColor(Color.WHITE);
- canvas.drawBitmap(bitmap, 0, 0, mTempPaint);
- canvas.drawColor(mColor);
-
- canvas.restore();
+ return new GlifPatternDrawable(colorPrimary);
+ }
+
+ @VisibleForTesting
+ public static void invalidatePattern() {
+ bitmapCache = null;
+ }
+
+ /* non-static section */
+
+ private int color;
+ private final Paint tempPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ public GlifPatternDrawable(int color) {
+ setColor(color);
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ final Rect bounds = getBounds();
+ int drawableWidth = bounds.width();
+ int drawableHeight = bounds.height();
+ Bitmap bitmap = null;
+ if (bitmapCache != null) {
+ bitmap = bitmapCache.get();
}
-
- @VisibleForTesting
- public Bitmap createBitmapCache(int drawableWidth, int drawableHeight) {
- float scaleX = drawableWidth / VIEWBOX_WIDTH;
- float scaleY = drawableHeight / VIEWBOX_HEIGHT;
- float scale = Math.max(scaleX, scaleY);
- scale = Math.min(MAX_CACHED_BITMAP_SCALE, scale);
-
-
- int scaledWidth = (int) (VIEWBOX_WIDTH * scale);
- int scaledHeight = (int) (VIEWBOX_HEIGHT * scale);
-
- // Use ALPHA_8 mask to save memory, since the pattern is grayscale only anyway.
- Bitmap bitmap = Bitmap.createBitmap(
- scaledWidth,
- scaledHeight,
- Bitmap.Config.ALPHA_8);
- Canvas bitmapCanvas = new Canvas(bitmap);
- renderOnCanvas(bitmapCanvas, scale);
- return bitmap;
+ if (bitmap != null) {
+ final int bitmapWidth = bitmap.getWidth();
+ final int bitmapHeight = bitmap.getHeight();
+ // Invalidate the cache if this drawable is bigger and we can still create a bigger
+ // cache.
+ if (drawableWidth > bitmapWidth && bitmapWidth < VIEWBOX_WIDTH * MAX_CACHED_BITMAP_SCALE) {
+ bitmap = null;
+ } else if (drawableHeight > bitmapHeight
+ && bitmapHeight < VIEWBOX_HEIGHT * MAX_CACHED_BITMAP_SCALE) {
+ bitmap = null;
+ }
}
- private void renderOnCanvas(Canvas canvas, float scale) {
- canvas.save();
- canvas.scale(scale, scale);
-
- mTempPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
-
- // Draw the pattern by creating the paths, adjusting the colors and drawing them. The path
- // values are extracted from the SVG of the pattern file.
-
- if (sPatternPaths == null) {
- sPatternPaths = new Path[NUM_PATHS];
- // Lightness values of the pattern, range 0 - 255
- sPatternLightness = new int[] { 10, 40, 51, 66, 91, 112, 130 };
-
- Path p = sPatternPaths[0] = new Path();
- p.moveTo(1029.4f, 357.5f);
- p.lineTo(1366f, 759.1f);
- p.lineTo(1366f, 0f);
- p.lineTo(1137.7f, 0f);
- p.close();
-
- p = sPatternPaths[1] = new Path();
- p.moveTo(1138.1f, 0f);
- p.rLineTo(-144.8f, 768f);
- p.rLineTo(372.7f, 0f);
- p.rLineTo(0f, -524f);
- p.cubicTo(1290.7f, 121.6f, 1219.2f, 41.1f, 1178.7f, 0f);
- p.close();
-
- p = sPatternPaths[2] = new Path();
- p.moveTo(949.8f, 768f);
- p.rCubicTo(92.6f, -170.6f, 213f, -440.3f, 269.4f, -768f);
- p.lineTo(585f, 0f);
- p.rLineTo(2.1f, 766f);
- p.close();
-
- p = sPatternPaths[3] = new Path();
- p.moveTo(471.1f, 768f);
- p.rMoveTo(704.5f, 0f);
- p.cubicTo(1123.6f, 563.3f, 1027.4f, 275.2f, 856.2f, 0f);
- p.lineTo(476.4f, 0f);
- p.rLineTo(-5.3f, 768f);
- p.close();
-
- p = sPatternPaths[4] = new Path();
- p.moveTo(323.1f, 768f);
- p.moveTo(777.5f, 768f);
- p.cubicTo(661.9f, 348.8f, 427.2f, 21.4f, 401.2f, 25.4f);
- p.lineTo(323.1f, 768f);
- p.close();
-
- p = sPatternPaths[5] = new Path();
- p.moveTo(178.44286f, 766.8571f);
- p.lineTo(308.7f, 768f);
- p.cubicTo(381.7f, 604.6f, 481.6f, 344.3f, 562.2f, 0f);
- p.lineTo(0f, 0f);
- p.close();
-
- p = sPatternPaths[6] = new Path();
- p.moveTo(146f, 0f);
- p.lineTo(0f, 0f);
- p.lineTo(0f, 768f);
- p.lineTo(394.2f, 768f);
- p.cubicTo(327.7f, 475.3f, 228.5f, 201f, 146f, 0f);
- p.close();
- }
-
- for (int i = 0; i < NUM_PATHS; i++) {
- // Color is 0xAARRGGBB, so alpha << 24 will create a color with (alpha)% black.
- // Although the color components don't really matter, since the backing bitmap cache is
- // ALPHA_8.
- mTempPaint.setColor(sPatternLightness[i] << 24);
- canvas.drawPath(sPatternPaths[i], mTempPaint);
- }
-
- canvas.restore();
- mTempPaint.reset();
- }
+ if (bitmap == null) {
+ // Reset the paint so it can be used to draw the paths in renderOnCanvas
+ tempPaint.reset();
- @VisibleForTesting
- public void scaleCanvasToBounds(Canvas canvas, Bitmap bitmap, Rect drawableBounds) {
- int bitmapWidth = bitmap.getWidth();
- int bitmapHeight = bitmap.getHeight();
- float scaleX = drawableBounds.width() / (float) bitmapWidth;
- float scaleY = drawableBounds.height() / (float) bitmapHeight;
-
- // First scale both sides to fit independently.
- canvas.scale(scaleX, scaleY);
- if (scaleY > scaleX) {
- // Adjust x-scale to maintain aspect ratio using the pivot, so that more of the texture
- // and less of the blank space on the left edge is seen.
- canvas.scale(scaleY / scaleX, 1f, SCALE_FOCUS_X * bitmapWidth, 0f);
- } else if (scaleX > scaleY) {
- // Adjust y-scale to maintain aspect ratio using the pivot, so that an intersection of
- // two "circles" can always be seen.
- canvas.scale(1f, scaleX / scaleY, 0f, SCALE_FOCUS_Y * bitmapHeight);
- }
- }
-
- @Override
- public void setAlpha(int i) {
- // Ignore
- }
+ bitmap = createBitmapCache(drawableWidth, drawableHeight);
+ bitmapCache = new SoftReference<>(bitmap);
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- // Ignore
+ // Reset the paint to so it can be used to draw the bitmap
+ tempPaint.reset();
}
- @Override
- public int getOpacity() {
- return PixelFormat.UNKNOWN;
+ canvas.save();
+ canvas.clipRect(bounds);
+
+ scaleCanvasToBounds(canvas, bitmap, bounds);
+ canvas.drawColor(Color.BLACK);
+ tempPaint.setColor(Color.WHITE);
+ canvas.drawBitmap(bitmap, 0, 0, tempPaint);
+ canvas.drawColor(color);
+
+ canvas.restore();
+ }
+
+ @VisibleForTesting
+ public Bitmap createBitmapCache(int drawableWidth, int drawableHeight) {
+ float scaleX = drawableWidth / VIEWBOX_WIDTH;
+ float scaleY = drawableHeight / VIEWBOX_HEIGHT;
+ float scale = Math.max(scaleX, scaleY);
+ scale = Math.min(MAX_CACHED_BITMAP_SCALE, scale);
+
+ int scaledWidth = (int) (VIEWBOX_WIDTH * scale);
+ int scaledHeight = (int) (VIEWBOX_HEIGHT * scale);
+
+ // Use ALPHA_8 mask to save memory, since the pattern is grayscale only anyway.
+ Bitmap bitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ALPHA_8);
+ Canvas bitmapCanvas = new Canvas(bitmap);
+ renderOnCanvas(bitmapCanvas, scale);
+ return bitmap;
+ }
+
+ private void renderOnCanvas(Canvas canvas, float scale) {
+ canvas.save();
+ canvas.scale(scale, scale);
+
+ tempPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+
+ // Draw the pattern by creating the paths, adjusting the colors and drawing them. The path
+ // values are extracted from the SVG of the pattern file.
+
+ if (patternPaths == null) {
+ patternPaths = new Path[NUM_PATHS];
+ // Lightness values of the pattern, range 0 - 255
+ patternLightness = new int[] {10, 40, 51, 66, 91, 112, 130};
+
+ Path p = patternPaths[0] = new Path();
+ p.moveTo(1029.4f, 357.5f);
+ p.lineTo(1366f, 759.1f);
+ p.lineTo(1366f, 0f);
+ p.lineTo(1137.7f, 0f);
+ p.close();
+
+ p = patternPaths[1] = new Path();
+ p.moveTo(1138.1f, 0f);
+ p.rLineTo(-144.8f, 768f);
+ p.rLineTo(372.7f, 0f);
+ p.rLineTo(0f, -524f);
+ p.cubicTo(1290.7f, 121.6f, 1219.2f, 41.1f, 1178.7f, 0f);
+ p.close();
+
+ p = patternPaths[2] = new Path();
+ p.moveTo(949.8f, 768f);
+ p.rCubicTo(92.6f, -170.6f, 213f, -440.3f, 269.4f, -768f);
+ p.lineTo(585f, 0f);
+ p.rLineTo(2.1f, 766f);
+ p.close();
+
+ p = patternPaths[3] = new Path();
+ p.moveTo(471.1f, 768f);
+ p.rMoveTo(704.5f, 0f);
+ p.cubicTo(1123.6f, 563.3f, 1027.4f, 275.2f, 856.2f, 0f);
+ p.lineTo(476.4f, 0f);
+ p.rLineTo(-5.3f, 768f);
+ p.close();
+
+ p = patternPaths[4] = new Path();
+ p.moveTo(323.1f, 768f);
+ p.moveTo(777.5f, 768f);
+ p.cubicTo(661.9f, 348.8f, 427.2f, 21.4f, 401.2f, 25.4f);
+ p.lineTo(323.1f, 768f);
+ p.close();
+
+ p = patternPaths[5] = new Path();
+ p.moveTo(178.44286f, 766.8571f);
+ p.lineTo(308.7f, 768f);
+ p.cubicTo(381.7f, 604.6f, 481.6f, 344.3f, 562.2f, 0f);
+ p.lineTo(0f, 0f);
+ p.close();
+
+ p = patternPaths[6] = new Path();
+ p.moveTo(146f, 0f);
+ p.lineTo(0f, 0f);
+ p.lineTo(0f, 768f);
+ p.lineTo(394.2f, 768f);
+ p.cubicTo(327.7f, 475.3f, 228.5f, 201f, 146f, 0f);
+ p.close();
}
- /**
- * Sets the color used as the base color of this pattern drawable. The alpha component of the
- * color will be ignored.
- */
- public void setColor(int color) {
- final int r = Color.red(color);
- final int g = Color.green(color);
- final int b = Color.blue(color);
- mColor = Color.argb(COLOR_ALPHA_INT, r, g, b);
- invalidateSelf();
+ for (int i = 0; i < NUM_PATHS; i++) {
+ // Color is 0xAARRGGBB, so alpha << 24 will create a color with (alpha)% black.
+ // Although the color components don't really matter, since the backing bitmap cache is
+ // ALPHA_8.
+ tempPaint.setColor(patternLightness[i] << 24);
+ canvas.drawPath(patternPaths[i], tempPaint);
}
- /**
- * @return The color used as the base color of this pattern drawable. The alpha component of
- * this is always 255.
- */
- public int getColor() {
- return Color.argb(255, Color.red(mColor), Color.green(mColor), Color.blue(mColor));
+ canvas.restore();
+ tempPaint.reset();
+ }
+
+ @VisibleForTesting
+ public void scaleCanvasToBounds(Canvas canvas, Bitmap bitmap, Rect drawableBounds) {
+ int bitmapWidth = bitmap.getWidth();
+ int bitmapHeight = bitmap.getHeight();
+ float scaleX = drawableBounds.width() / (float) bitmapWidth;
+ float scaleY = drawableBounds.height() / (float) bitmapHeight;
+
+ // First scale both sides to fit independently.
+ canvas.scale(scaleX, scaleY);
+ if (scaleY > scaleX) {
+ // Adjust x-scale to maintain aspect ratio using the pivot, so that more of the texture
+ // and less of the blank space on the left edge is seen.
+ canvas.scale(scaleY / scaleX, 1f, SCALE_FOCUS_X * bitmapWidth, 0f);
+ } else if (scaleX > scaleY) {
+ // Adjust y-scale to maintain aspect ratio using the pivot, so that an intersection of
+ // two "circles" can always be seen.
+ canvas.scale(1f, scaleX / scaleY, 0f, SCALE_FOCUS_Y * bitmapHeight);
}
+ }
+
+ @Override
+ public void setAlpha(int i) {
+ // Ignore
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ // Ignore
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.UNKNOWN;
+ }
+
+ /**
+ * Sets the color used as the base color of this pattern drawable. The alpha component of the
+ * color will be ignored.
+ */
+ public void setColor(int color) {
+ final int r = Color.red(color);
+ final int g = Color.green(color);
+ final int b = Color.blue(color);
+ this.color = Color.argb(COLOR_ALPHA_INT, r, g, b);
+ invalidateSelf();
+ }
+
+ /**
+ * @return The color used as the base color of this pattern drawable. The alpha component of this
+ * is always 255.
+ */
+ public int getColor() {
+ return Color.argb(255, Color.red(color), Color.green(color), Color.blue(color));
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java b/library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java
index d520873..6197c4c 100644
--- a/library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java
+++ b/library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java
@@ -17,34 +17,30 @@
package com.android.setupwizardlib;
import android.content.Context;
+import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.ListAdapter;
-
-import androidx.annotation.Nullable;
-
import com.android.setupwizardlib.items.ItemAdapter;
-/**
- * @deprecated Use {@link SetupWizardListLayout} instead.
- */
+/** @deprecated Use {@link SetupWizardListLayout} instead. */
@Deprecated
public class SetupWizardItemsLayout extends SetupWizardListLayout {
- public SetupWizardItemsLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
+ public SetupWizardItemsLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
- public SetupWizardItemsLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
+ public SetupWizardItemsLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
- @Override
- @Nullable
- public ItemAdapter getAdapter() {
- final ListAdapter adapter = super.getAdapter();
- if (adapter instanceof ItemAdapter) {
- return (ItemAdapter) adapter;
- }
- return null;
+ @Override
+ @Nullable
+ public ItemAdapter getAdapter() {
+ final ListAdapter adapter = super.getAdapter();
+ if (adapter instanceof ItemAdapter) {
+ return (ItemAdapter) adapter;
}
+ return null;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/SetupWizardLayout.java b/library/main/src/com/android/setupwizardlib/SetupWizardLayout.java
index 065d2ef..792d102 100644
--- a/library/main/src/com/android/setupwizardlib/SetupWizardLayout.java
+++ b/library/main/src/com/android/setupwizardlib/SetupWizardLayout.java
@@ -38,7 +38,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
import android.widget.TextView;
-
import com.android.setupwizardlib.template.HeaderMixin;
import com.android.setupwizardlib.template.NavigationBarMixin;
import com.android.setupwizardlib.template.ProgressBarMixin;
@@ -49,385 +48,377 @@ import com.android.setupwizardlib.view.NavigationBar;
public class SetupWizardLayout extends TemplateLayout {
- private static final String TAG = "SetupWizardLayout";
-
- public SetupWizardLayout(Context context) {
- super(context, 0, 0);
- init(null, R.attr.suwLayoutTheme);
- }
-
- public SetupWizardLayout(Context context, int template) {
- this(context, template, 0);
- }
-
- public SetupWizardLayout(Context context, int template, int containerId) {
- super(context, template, containerId);
- init(null, R.attr.suwLayoutTheme);
- }
-
- public SetupWizardLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs, R.attr.suwLayoutTheme);
- }
-
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public SetupWizardLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(attrs, defStyleAttr);
- }
-
- // All the constructors delegate to this init method. The 3-argument constructor is not
- // available in LinearLayout before v11, so call super with the exact same arguments.
- private void init(AttributeSet attrs, int defStyleAttr) {
- registerMixin(HeaderMixin.class, new HeaderMixin(this, attrs, defStyleAttr));
- registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
- registerMixin(NavigationBarMixin.class, new NavigationBarMixin(this));
- final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this);
- registerMixin(RequireScrollMixin.class, requireScrollMixin);
-
- final ScrollView scrollView = getScrollView();
- if (scrollView != null) {
- requireScrollMixin.setScrollHandlingDelegate(
- new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView));
- }
-
- final TypedArray a = getContext().obtainStyledAttributes(attrs,
- R.styleable.SuwSetupWizardLayout, defStyleAttr, 0);
-
- // Set the background from XML, either directly or built from a bitmap tile
- final Drawable background =
- a.getDrawable(R.styleable.SuwSetupWizardLayout_suwBackground);
- if (background != null) {
- setLayoutBackground(background);
- } else {
- final Drawable backgroundTile =
- a.getDrawable(R.styleable.SuwSetupWizardLayout_suwBackgroundTile);
- if (backgroundTile != null) {
- setBackgroundTile(backgroundTile);
- }
- }
-
- // Set the illustration from XML, either directly or built from image + horizontal tile
- final Drawable illustration =
- a.getDrawable(R.styleable.SuwSetupWizardLayout_suwIllustration);
- if (illustration != null) {
- setIllustration(illustration);
- } else {
- final Drawable illustrationImage =
- a.getDrawable(R.styleable.SuwSetupWizardLayout_suwIllustrationImage);
- final Drawable horizontalTile = a.getDrawable(
- R.styleable.SuwSetupWizardLayout_suwIllustrationHorizontalTile);
- if (illustrationImage != null && horizontalTile != null) {
- setIllustration(illustrationImage, horizontalTile);
- }
- }
-
- // Set the top padding of the illustration
- int decorPaddingTop = a.getDimensionPixelSize(
- R.styleable.SuwSetupWizardLayout_suwDecorPaddingTop, -1);
- if (decorPaddingTop == -1) {
- decorPaddingTop = getResources().getDimensionPixelSize(R.dimen.suw_decor_padding_top);
- }
- setDecorPaddingTop(decorPaddingTop);
-
-
- // Set the illustration aspect ratio. See Illustration.setAspectRatio(float). This will
- // override suwDecorPaddingTop if its value is not 0.
- float illustrationAspectRatio = a.getFloat(
- R.styleable.SuwSetupWizardLayout_suwIllustrationAspectRatio, -1f);
- if (illustrationAspectRatio == -1f) {
- final TypedValue out = new TypedValue();
- getResources().getValue(R.dimen.suw_illustration_aspect_ratio, out, true);
- illustrationAspectRatio = out.getFloat();
- }
- setIllustrationAspectRatio(illustrationAspectRatio);
-
- a.recycle();
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- final Parcelable parcelable = super.onSaveInstanceState();
- final SavedState ss = new SavedState(parcelable);
- ss.mIsProgressBarShown = isProgressBarShown();
- return ss;
+ private static final String TAG = "SetupWizardLayout";
+
+ public SetupWizardLayout(Context context) {
+ super(context, 0, 0);
+ init(null, R.attr.suwLayoutTheme);
+ }
+
+ public SetupWizardLayout(Context context, int template) {
+ this(context, template, 0);
+ }
+
+ public SetupWizardLayout(Context context, int template, int containerId) {
+ super(context, template, containerId);
+ init(null, R.attr.suwLayoutTheme);
+ }
+
+ public SetupWizardLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, R.attr.suwLayoutTheme);
+ }
+
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public SetupWizardLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ // All the constructors delegate to this init method. The 3-argument constructor is not
+ // available in LinearLayout before v11, so call super with the exact same arguments.
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ registerMixin(HeaderMixin.class, new HeaderMixin(this, attrs, defStyleAttr));
+ registerMixin(ProgressBarMixin.class, new ProgressBarMixin(this));
+ registerMixin(NavigationBarMixin.class, new NavigationBarMixin(this));
+ final RequireScrollMixin requireScrollMixin = new RequireScrollMixin(this);
+ registerMixin(RequireScrollMixin.class, requireScrollMixin);
+
+ final ScrollView scrollView = getScrollView();
+ if (scrollView != null) {
+ requireScrollMixin.setScrollHandlingDelegate(
+ new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView));
+ }
+
+ final TypedArray a =
+ getContext()
+ .obtainStyledAttributes(attrs, R.styleable.SuwSetupWizardLayout, defStyleAttr, 0);
+
+ // Set the background from XML, either directly or built from a bitmap tile
+ final Drawable background = a.getDrawable(R.styleable.SuwSetupWizardLayout_suwBackground);
+ if (background != null) {
+ setLayoutBackground(background);
+ } else {
+ final Drawable backgroundTile =
+ a.getDrawable(R.styleable.SuwSetupWizardLayout_suwBackgroundTile);
+ if (backgroundTile != null) {
+ setBackgroundTile(backgroundTile);
+ }
+ }
+
+ // Set the illustration from XML, either directly or built from image + horizontal tile
+ final Drawable illustration = a.getDrawable(R.styleable.SuwSetupWizardLayout_suwIllustration);
+ if (illustration != null) {
+ setIllustration(illustration);
+ } else {
+ final Drawable illustrationImage =
+ a.getDrawable(R.styleable.SuwSetupWizardLayout_suwIllustrationImage);
+ final Drawable horizontalTile =
+ a.getDrawable(R.styleable.SuwSetupWizardLayout_suwIllustrationHorizontalTile);
+ if (illustrationImage != null && horizontalTile != null) {
+ setIllustration(illustrationImage, horizontalTile);
+ }
+ }
+
+ // Set the top padding of the illustration
+ int decorPaddingTop =
+ a.getDimensionPixelSize(R.styleable.SuwSetupWizardLayout_suwDecorPaddingTop, -1);
+ if (decorPaddingTop == -1) {
+ decorPaddingTop = getResources().getDimensionPixelSize(R.dimen.suw_decor_padding_top);
+ }
+ setDecorPaddingTop(decorPaddingTop);
+
+ // Set the illustration aspect ratio. See Illustration.setAspectRatio(float). This will
+ // override suwDecorPaddingTop if its value is not 0.
+ float illustrationAspectRatio =
+ a.getFloat(R.styleable.SuwSetupWizardLayout_suwIllustrationAspectRatio, -1f);
+ if (illustrationAspectRatio == -1f) {
+ final TypedValue out = new TypedValue();
+ getResources().getValue(R.dimen.suw_illustration_aspect_ratio, out, true);
+ illustrationAspectRatio = out.getFloat();
+ }
+ setIllustrationAspectRatio(illustrationAspectRatio);
+
+ a.recycle();
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable parcelable = super.onSaveInstanceState();
+ final SavedState ss = new SavedState(parcelable);
+ ss.isProgressBarShown = isProgressBarShown();
+ return ss;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (!(state instanceof SavedState)) {
+ Log.w(TAG, "Ignoring restore instance state " + state);
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ final SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(ss.getSuperState());
+ final boolean isProgressBarShown = ss.isProgressBarShown;
+ setProgressBarShown(isProgressBarShown);
+ }
+
+ @Override
+ protected View onInflateTemplate(LayoutInflater inflater, int template) {
+ if (template == 0) {
+ template = R.layout.suw_template;
+ }
+ return inflateTemplate(inflater, R.style.SuwThemeMaterial_Light, template);
+ }
+
+ @Override
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ containerId = R.id.suw_layout_content;
+ }
+ return super.findContainer(containerId);
+ }
+
+ public NavigationBar getNavigationBar() {
+ return getMixin(NavigationBarMixin.class).getNavigationBar();
+ }
+
+ public ScrollView getScrollView() {
+ final View view = findManagedViewById(R.id.suw_bottom_scroll_view);
+ return view instanceof ScrollView ? (ScrollView) view : null;
+ }
+
+ public void requireScrollToBottom() {
+ final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
+ final NavigationBar navigationBar = getNavigationBar();
+ if (navigationBar != null) {
+ requireScrollMixin.requireScrollWithNavigationBar(navigationBar);
+ } else {
+ Log.e(TAG, "Cannot require scroll. Navigation bar is null.");
+ }
+ }
+
+ public void setHeaderText(int title) {
+ getMixin(HeaderMixin.class).setText(title);
+ }
+
+ public void setHeaderText(CharSequence title) {
+ getMixin(HeaderMixin.class).setText(title);
+ }
+
+ public CharSequence getHeaderText() {
+ return getMixin(HeaderMixin.class).getText();
+ }
+
+ public TextView getHeaderTextView() {
+ return getMixin(HeaderMixin.class).getTextView();
+ }
+
+ /**
+ * Set the illustration of the layout. The drawable will be applied as is, and the bounds will be
+ * set as implemented in {@link com.android.setupwizardlib.view.Illustration}. To create a
+ * suitable drawable from an asset and a horizontal repeating tile, use {@link
+ * #setIllustration(int, int)} instead.
+ *
+ * @param drawable The drawable specifying the illustration.
+ */
+ public void setIllustration(Drawable drawable) {
+ final View view = findManagedViewById(R.id.suw_layout_decor);
+ if (view instanceof Illustration) {
+ final Illustration illustration = (Illustration) view;
+ illustration.setIllustration(drawable);
+ }
+ }
+
+ /**
+ * Set the illustration of the layout, which will be created asset and the horizontal tile as
+ * suitable. On phone layouts (not sw600dp), the asset will be scaled, maintaining aspect ratio.
+ * On tablets (sw600dp), the assets will always have 256dp height and the rest of the illustration
+ * area that the asset doesn't fill will be covered by the horizontalTile.
+ *
+ * @param asset Resource ID of the illustration asset.
+ * @param horizontalTile Resource ID of the horizontally repeating tile for tablet layout.
+ */
+ public void setIllustration(int asset, int horizontalTile) {
+ final View view = findManagedViewById(R.id.suw_layout_decor);
+ if (view instanceof Illustration) {
+ final Illustration illustration = (Illustration) view;
+ final Drawable illustrationDrawable = getIllustration(asset, horizontalTile);
+ illustration.setIllustration(illustrationDrawable);
+ }
+ }
+
+ private void setIllustration(Drawable asset, Drawable horizontalTile) {
+ final View view = findManagedViewById(R.id.suw_layout_decor);
+ if (view instanceof Illustration) {
+ final Illustration illustration = (Illustration) view;
+ final Drawable illustrationDrawable = getIllustration(asset, horizontalTile);
+ illustration.setIllustration(illustrationDrawable);
+ }
+ }
+
+ /**
+ * Sets the aspect ratio of the illustration. This will be the space (padding top) reserved above
+ * the header text. This will override the padding top of the illustration.
+ *
+ * @param aspectRatio The aspect ratio
+ * @see com.android.setupwizardlib.view.Illustration#setAspectRatio(float)
+ */
+ public void setIllustrationAspectRatio(float aspectRatio) {
+ final View view = findManagedViewById(R.id.suw_layout_decor);
+ if (view instanceof Illustration) {
+ final Illustration illustration = (Illustration) view;
+ illustration.setAspectRatio(aspectRatio);
+ }
+ }
+
+ /**
+ * Set the top padding of the decor view. If the decor is an Illustration and the aspect ratio is
+ * set, this value will be overridden.
+ *
+ * <p>Note: Currently the default top padding for tablet landscape is 128dp, which is the offset
+ * of the card from the top. This is likely to change in future versions so this value aligns with
+ * the height of the illustration instead.
+ *
+ * @param paddingTop The top padding in pixels.
+ */
+ public void setDecorPaddingTop(int paddingTop) {
+ final View view = findManagedViewById(R.id.suw_layout_decor);
+ if (view != null) {
+ view.setPadding(
+ view.getPaddingLeft(), paddingTop, view.getPaddingRight(), view.getPaddingBottom());
+ }
+ }
+
+ /**
+ * Set the background of the layout, which is expected to be able to extend infinitely. If it is a
+ * bitmap tile and you want it to repeat, use {@link #setBackgroundTile(int)} instead.
+ */
+ public void setLayoutBackground(Drawable background) {
+ final View view = findManagedViewById(R.id.suw_layout_decor);
+ if (view != null) {
+ //noinspection deprecation
+ view.setBackgroundDrawable(background);
+ }
+ }
+
+ /**
+ * Set the background of the layout to a repeating bitmap tile. To use a different kind of
+ * drawable, use {@link #setLayoutBackground(android.graphics.drawable.Drawable)} instead.
+ */
+ public void setBackgroundTile(int backgroundTile) {
+ final Drawable backgroundTileDrawable = getContext().getResources().getDrawable(backgroundTile);
+ setBackgroundTile(backgroundTileDrawable);
+ }
+
+ private void setBackgroundTile(Drawable backgroundTile) {
+ if (backgroundTile instanceof BitmapDrawable) {
+ ((BitmapDrawable) backgroundTile).setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
+ }
+ setLayoutBackground(backgroundTile);
+ }
+
+ private Drawable getIllustration(int asset, int horizontalTile) {
+ final Context context = getContext();
+ final Drawable assetDrawable = context.getResources().getDrawable(asset);
+ final Drawable tile = context.getResources().getDrawable(horizontalTile);
+ return getIllustration(assetDrawable, tile);
+ }
+
+ @SuppressLint("RtlHardcoded")
+ private Drawable getIllustration(Drawable asset, Drawable horizontalTile) {
+ final Context context = getContext();
+ if (context.getResources().getBoolean(R.bool.suwUseTabletLayout)) {
+ // If it is a "tablet" (sw600dp), create a LayerDrawable with the horizontal tile.
+ if (horizontalTile instanceof BitmapDrawable) {
+ ((BitmapDrawable) horizontalTile).setTileModeX(TileMode.REPEAT);
+ ((BitmapDrawable) horizontalTile).setGravity(Gravity.TOP);
+ }
+ if (asset instanceof BitmapDrawable) {
+ // Always specify TOP | LEFT, Illustration will flip the entire LayerDrawable.
+ ((BitmapDrawable) asset).setGravity(Gravity.TOP | Gravity.LEFT);
+ }
+ final LayerDrawable layers = new LayerDrawable(new Drawable[] {horizontalTile, asset});
+ if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ layers.setAutoMirrored(true);
+ }
+ return layers;
+ } else {
+ // If it is a "phone" (not sw600dp), simply return the illustration
+ if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ asset.setAutoMirrored(true);
+ }
+ return asset;
+ }
+ }
+
+ public boolean isProgressBarShown() {
+ return getMixin(ProgressBarMixin.class).isShown();
+ }
+
+ /**
+ * Sets whether the progress bar below the header text is shown or not. The progress bar is a
+ * lazily inflated ViewStub, which means the progress bar will not actually be part of the view
+ * hierarchy until the first time this is set to {@code true}.
+ */
+ public void setProgressBarShown(boolean shown) {
+ getMixin(ProgressBarMixin.class).setShown(shown);
+ }
+
+ /** @deprecated Use {@link #setProgressBarShown(boolean)} */
+ @Deprecated
+ public void showProgressBar() {
+ setProgressBarShown(true);
+ }
+
+ /** @deprecated Use {@link #setProgressBarShown(boolean)} */
+ @Deprecated
+ public void hideProgressBar() {
+ setProgressBarShown(false);
+ }
+
+ public void setProgressBarColor(ColorStateList color) {
+ getMixin(ProgressBarMixin.class).setColor(color);
+ }
+
+ public ColorStateList getProgressBarColor() {
+ return getMixin(ProgressBarMixin.class).getColor();
+ }
+
+ /* Misc */
+
+ protected static class SavedState extends BaseSavedState {
+
+ boolean isProgressBarShown = false;
+
+ public SavedState(Parcelable parcelable) {
+ super(parcelable);
+ }
+
+ public SavedState(Parcel source) {
+ super(source);
+ isProgressBarShown = source.readInt() != 0;
}
@Override
- protected void onRestoreInstanceState(Parcelable state) {
- if (!(state instanceof SavedState)) {
- Log.w(TAG, "Ignoring restore instance state " + state);
- super.onRestoreInstanceState(state);
- return;
- }
-
- final SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- final boolean isProgressBarShown = ss.mIsProgressBarShown;
- setProgressBarShown(isProgressBarShown);
- }
-
- @Override
- protected View onInflateTemplate(LayoutInflater inflater, int template) {
- if (template == 0) {
- template = R.layout.suw_template;
- }
- return inflateTemplate(inflater, R.style.SuwThemeMaterial_Light, template);
- }
-
- @Override
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- containerId = R.id.suw_layout_content;
- }
- return super.findContainer(containerId);
- }
-
- public NavigationBar getNavigationBar() {
- return getMixin(NavigationBarMixin.class).getNavigationBar();
- }
-
- public ScrollView getScrollView() {
- final View view = findManagedViewById(R.id.suw_bottom_scroll_view);
- return view instanceof ScrollView ? (ScrollView) view : null;
- }
-
- public void requireScrollToBottom() {
- final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
- final NavigationBar navigationBar = getNavigationBar();
- if (navigationBar != null) {
- requireScrollMixin.requireScrollWithNavigationBar(navigationBar);
- } else {
- Log.e(TAG, "Cannot require scroll. Navigation bar is null.");
- }
- }
-
- public void setHeaderText(int title) {
- getMixin(HeaderMixin.class).setText(title);
- }
-
- public void setHeaderText(CharSequence title) {
- getMixin(HeaderMixin.class).setText(title);
- }
-
- public CharSequence getHeaderText() {
- return getMixin(HeaderMixin.class).getText();
- }
-
- public TextView getHeaderTextView() {
- return getMixin(HeaderMixin.class).getTextView();
- }
-
- /**
- * Set the illustration of the layout. The drawable will be applied as is, and the bounds will
- * be set as implemented in {@link com.android.setupwizardlib.view.Illustration}. To create
- * a suitable drawable from an asset and a horizontal repeating tile, use
- * {@link #setIllustration(int, int)} instead.
- *
- * @param drawable The drawable specifying the illustration.
- */
- public void setIllustration(Drawable drawable) {
- final View view = findManagedViewById(R.id.suw_layout_decor);
- if (view instanceof Illustration) {
- final Illustration illustration = (Illustration) view;
- illustration.setIllustration(drawable);
- }
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(isProgressBarShown ? 1 : 0);
}
- /**
- * Set the illustration of the layout, which will be created asset and the horizontal tile as
- * suitable. On phone layouts (not sw600dp), the asset will be scaled, maintaining aspect ratio.
- * On tablets (sw600dp), the assets will always have 256dp height and the rest of the
- * illustration area that the asset doesn't fill will be covered by the horizontalTile.
- *
- * @param asset Resource ID of the illustration asset.
- * @param horizontalTile Resource ID of the horizontally repeating tile for tablet layout.
- */
- public void setIllustration(int asset, int horizontalTile) {
- final View view = findManagedViewById(R.id.suw_layout_decor);
- if (view instanceof Illustration) {
- final Illustration illustration = (Illustration) view;
- final Drawable illustrationDrawable = getIllustration(asset, horizontalTile);
- illustration.setIllustration(illustrationDrawable);
- }
- }
-
- private void setIllustration(Drawable asset, Drawable horizontalTile) {
- final View view = findManagedViewById(R.id.suw_layout_decor);
- if (view instanceof Illustration) {
- final Illustration illustration = (Illustration) view;
- final Drawable illustrationDrawable = getIllustration(asset, horizontalTile);
- illustration.setIllustration(illustrationDrawable);
- }
- }
-
- /**
- * Sets the aspect ratio of the illustration. This will be the space (padding top) reserved
- * above the header text. This will override the padding top of the illustration.
- *
- * @param aspectRatio The aspect ratio
- * @see com.android.setupwizardlib.view.Illustration#setAspectRatio(float)
- */
- public void setIllustrationAspectRatio(float aspectRatio) {
- final View view = findManagedViewById(R.id.suw_layout_decor);
- if (view instanceof Illustration) {
- final Illustration illustration = (Illustration) view;
- illustration.setAspectRatio(aspectRatio);
- }
- }
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
- /**
- * Set the top padding of the decor view. If the decor is an Illustration and the aspect ratio
- * is set, this value will be overridden.
- *
- * <p>Note: Currently the default top padding for tablet landscape is 128dp, which is the offset
- * of the card from the top. This is likely to change in future versions so this value aligns
- * with the height of the illustration instead.
- *
- * @param paddingTop The top padding in pixels.
- */
- public void setDecorPaddingTop(int paddingTop) {
- final View view = findManagedViewById(R.id.suw_layout_decor);
- if (view != null) {
- view.setPadding(view.getPaddingLeft(), paddingTop, view.getPaddingRight(),
- view.getPaddingBottom());
- }
- }
-
- /**
- * Set the background of the layout, which is expected to be able to extend infinitely. If it is
- * a bitmap tile and you want it to repeat, use {@link #setBackgroundTile(int)} instead.
- */
- public void setLayoutBackground(Drawable background) {
- final View view = findManagedViewById(R.id.suw_layout_decor);
- if (view != null) {
- //noinspection deprecation
- view.setBackgroundDrawable(background);
- }
- }
-
- /**
- * Set the background of the layout to a repeating bitmap tile. To use a different kind of
- * drawable, use {@link #setLayoutBackground(android.graphics.drawable.Drawable)} instead.
- */
- public void setBackgroundTile(int backgroundTile) {
- final Drawable backgroundTileDrawable =
- getContext().getResources().getDrawable(backgroundTile);
- setBackgroundTile(backgroundTileDrawable);
- }
+ @Override
+ public SavedState createFromParcel(Parcel parcel) {
+ return new SavedState(parcel);
+ }
- private void setBackgroundTile(Drawable backgroundTile) {
- if (backgroundTile instanceof BitmapDrawable) {
- ((BitmapDrawable) backgroundTile).setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
- }
- setLayoutBackground(backgroundTile);
- }
-
- private Drawable getIllustration(int asset, int horizontalTile) {
- final Context context = getContext();
- final Drawable assetDrawable = context.getResources().getDrawable(asset);
- final Drawable tile = context.getResources().getDrawable(horizontalTile);
- return getIllustration(assetDrawable, tile);
- }
-
- @SuppressLint("RtlHardcoded")
- private Drawable getIllustration(Drawable asset, Drawable horizontalTile) {
- final Context context = getContext();
- if (context.getResources().getBoolean(R.bool.suwUseTabletLayout)) {
- // If it is a "tablet" (sw600dp), create a LayerDrawable with the horizontal tile.
- if (horizontalTile instanceof BitmapDrawable) {
- ((BitmapDrawable) horizontalTile).setTileModeX(TileMode.REPEAT);
- ((BitmapDrawable) horizontalTile).setGravity(Gravity.TOP);
- }
- if (asset instanceof BitmapDrawable) {
- // Always specify TOP | LEFT, Illustration will flip the entire LayerDrawable.
- ((BitmapDrawable) asset).setGravity(Gravity.TOP | Gravity.LEFT);
- }
- final LayerDrawable layers =
- new LayerDrawable(new Drawable[] { horizontalTile, asset });
- if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- layers.setAutoMirrored(true);
- }
- return layers;
- } else {
- // If it is a "phone" (not sw600dp), simply return the illustration
- if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- asset.setAutoMirrored(true);
- }
- return asset;
- }
- }
-
- public boolean isProgressBarShown() {
- return getMixin(ProgressBarMixin.class).isShown();
- }
-
- /**
- * Sets whether the progress bar below the header text is shown or not. The progress bar is
- * a lazily inflated ViewStub, which means the progress bar will not actually be part of the
- * view hierarchy until the first time this is set to {@code true}.
- */
- public void setProgressBarShown(boolean shown) {
- getMixin(ProgressBarMixin.class).setShown(shown);
- }
-
- /**
- * @deprecated Use {@link #setProgressBarShown(boolean)}
- */
- @Deprecated
- public void showProgressBar() {
- setProgressBarShown(true);
- }
-
- /**
- * @deprecated Use {@link #setProgressBarShown(boolean)}
- */
- @Deprecated
- public void hideProgressBar() {
- setProgressBarShown(false);
- }
-
- public void setProgressBarColor(ColorStateList color) {
- getMixin(ProgressBarMixin.class).setColor(color);
- }
-
- public ColorStateList getProgressBarColor() {
- return getMixin(ProgressBarMixin.class).getColor();
- }
-
- /* Misc */
-
- protected static class SavedState extends BaseSavedState {
-
- boolean mIsProgressBarShown = false;
-
- public SavedState(Parcelable parcelable) {
- super(parcelable);
- }
-
- public SavedState(Parcel source) {
- super(source);
- mIsProgressBarShown = source.readInt() != 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
- dest.writeInt(mIsProgressBarShown ? 1 : 0);
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Parcelable.Creator<SavedState>() {
-
- @Override
- public SavedState createFromParcel(Parcel parcel) {
- return new SavedState(parcel);
- }
-
- @Override
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/SetupWizardListLayout.java b/library/main/src/com/android/setupwizardlib/SetupWizardListLayout.java
index 050d566..f1c7e11 100644
--- a/library/main/src/com/android/setupwizardlib/SetupWizardListLayout.java
+++ b/library/main/src/com/android/setupwizardlib/SetupWizardListLayout.java
@@ -26,141 +26,128 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
-
import com.android.setupwizardlib.template.ListMixin;
import com.android.setupwizardlib.template.ListViewScrollHandlingDelegate;
import com.android.setupwizardlib.template.RequireScrollMixin;
public class SetupWizardListLayout extends SetupWizardLayout {
- private static final String TAG = "SetupWizardListLayout";
-
- private ListMixin mListMixin;
-
- public SetupWizardListLayout(Context context) {
- this(context, 0, 0);
- }
-
- public SetupWizardListLayout(Context context, int template) {
- this(context, template, 0);
- }
-
- public SetupWizardListLayout(Context context, int template, int containerId) {
- super(context, template, containerId);
- init(context, null, 0);
- }
-
- public SetupWizardListLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs, 0);
- }
-
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public SetupWizardListLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs, defStyleAttr);
- }
-
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- mListMixin = new ListMixin(this, attrs, defStyleAttr);
- registerMixin(ListMixin.class, mListMixin);
-
- final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
- requireScrollMixin.setScrollHandlingDelegate(
- new ListViewScrollHandlingDelegate(requireScrollMixin, getListView()));
- }
-
- @Override
- protected View onInflateTemplate(LayoutInflater inflater, int template) {
- if (template == 0) {
- template = R.layout.suw_list_template;
- }
- return super.onInflateTemplate(inflater, template);
- }
-
- @Override
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- containerId = android.R.id.list;
- }
- return super.findContainer(containerId);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- mListMixin.onLayout();
- }
-
- public ListView getListView() {
- return mListMixin.getListView();
- }
-
- public void setAdapter(ListAdapter adapter) {
- mListMixin.setAdapter(adapter);
- }
-
- public ListAdapter getAdapter() {
- return mListMixin.getAdapter();
- }
-
- /**
- * Sets the start inset of the divider. This will use the default divider drawable set in the
- * theme and inset it {@code inset} pixels to the right (or left in RTL layouts).
- *
- * @param inset The number of pixels to inset on the "start" side of the list divider. Typically
- * this will be either {@code @dimen/suw_items_icon_divider_inset} or
- * {@code @dimen/suw_items_text_divider_inset}.
- *
- * @see ListMixin#setDividerInset(int)
- * @deprecated Use {@link #setDividerInsets(int, int)} instead.
- */
- @Deprecated
- public void setDividerInset(int inset) {
- mListMixin.setDividerInset(inset);
- }
-
- /**
- * Sets the start inset of the divider. This will use the default divider drawable set in the
- * theme and apply insets to it.
- *
- * @param start The number of pixels to inset on the "start" side of the list divider. Typically
- * this will be either {@code @dimen/suw_items_icon_divider_inset} or
- * {@code @dimen/suw_items_text_divider_inset}.
- * @param end The number of pixels to inset on the "end" side of the list divider.
- *
- * @see ListMixin#setDividerInsets(int, int)
- */
- public void setDividerInsets(int start, int end) {
- mListMixin.setDividerInsets(start, end);
- }
-
- /**
- * @deprecated Use {@link #getDividerInsetStart()} instead.
- */
- @Deprecated
- public int getDividerInset() {
- return mListMixin.getDividerInset();
- }
-
- /**
- * @see ListMixin#getDividerInsetStart()
- */
- public int getDividerInsetStart() {
- return mListMixin.getDividerInsetStart();
- }
-
- /**
- * @see ListMixin#getDividerInsetEnd()
- */
- public int getDividerInsetEnd() {
- return mListMixin.getDividerInsetEnd();
- }
-
- /**
- * @see ListMixin#getDivider()
- */
- public Drawable getDivider() {
- return mListMixin.getDivider();
- }
+ private ListMixin listMixin;
+
+ public SetupWizardListLayout(Context context) {
+ this(context, 0, 0);
+ }
+
+ public SetupWizardListLayout(Context context, int template) {
+ this(context, template, 0);
+ }
+
+ public SetupWizardListLayout(Context context, int template, int containerId) {
+ super(context, template, containerId);
+ init(null, 0);
+ }
+
+ public SetupWizardListLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public SetupWizardListLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ listMixin = new ListMixin(this, attrs, defStyleAttr);
+ registerMixin(ListMixin.class, listMixin);
+
+ final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
+ requireScrollMixin.setScrollHandlingDelegate(
+ new ListViewScrollHandlingDelegate(requireScrollMixin, getListView()));
+ }
+
+ @Override
+ protected View onInflateTemplate(LayoutInflater inflater, int template) {
+ if (template == 0) {
+ template = R.layout.suw_list_template;
+ }
+ return super.onInflateTemplate(inflater, template);
+ }
+
+ @Override
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ containerId = android.R.id.list;
+ }
+ return super.findContainer(containerId);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ listMixin.onLayout();
+ }
+
+ public ListView getListView() {
+ return listMixin.getListView();
+ }
+
+ public void setAdapter(ListAdapter adapter) {
+ listMixin.setAdapter(adapter);
+ }
+
+ public ListAdapter getAdapter() {
+ return listMixin.getAdapter();
+ }
+
+ /**
+ * Sets the start inset of the divider. This will use the default divider drawable set in the
+ * theme and inset it {@code inset} pixels to the right (or left in RTL layouts).
+ *
+ * @param inset The number of pixels to inset on the "start" side of the list divider. Typically
+ * this will be either {@code @dimen/suw_items_icon_divider_inset} or
+ * {@code @dimen/suw_items_text_divider_inset}.
+ * @see ListMixin#setDividerInset(int)
+ * @deprecated Use {@link #setDividerInsets(int, int)} instead.
+ */
+ @Deprecated
+ public void setDividerInset(int inset) {
+ listMixin.setDividerInset(inset);
+ }
+
+ /**
+ * Sets the start inset of the divider. This will use the default divider drawable set in the
+ * theme and apply insets to it.
+ *
+ * @param start The number of pixels to inset on the "start" side of the list divider. Typically
+ * this will be either {@code @dimen/suw_items_icon_divider_inset} or
+ * {@code @dimen/suw_items_text_divider_inset}.
+ * @param end The number of pixels to inset on the "end" side of the list divider.
+ * @see ListMixin#setDividerInsets(int, int)
+ */
+ public void setDividerInsets(int start, int end) {
+ listMixin.setDividerInsets(start, end);
+ }
+
+ /** @deprecated Use {@link #getDividerInsetStart()} instead. */
+ @Deprecated
+ public int getDividerInset() {
+ return listMixin.getDividerInset();
+ }
+
+ /** @see ListMixin#getDividerInsetStart() */
+ public int getDividerInsetStart() {
+ return listMixin.getDividerInsetStart();
+ }
+
+ /** @see ListMixin#getDividerInsetEnd() */
+ public int getDividerInsetEnd() {
+ return listMixin.getDividerInsetEnd();
+ }
+
+ /** @see ListMixin#getDivider() */
+ public Drawable getDivider() {
+ return listMixin.getDivider();
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/TemplateLayout.java b/library/main/src/com/android/setupwizardlib/TemplateLayout.java
index 0108880..c53e176 100644
--- a/library/main/src/com/android/setupwizardlib/TemplateLayout.java
+++ b/library/main/src/com/android/setupwizardlib/TemplateLayout.java
@@ -20,256 +20,249 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build.VERSION_CODES;
+import androidx.annotation.Keep;
+import androidx.annotation.LayoutRes;
+import androidx.annotation.StyleRes;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
-
-import androidx.annotation.Keep;
-import androidx.annotation.LayoutRes;
-import androidx.annotation.StyleRes;
-
import com.android.setupwizardlib.template.Mixin;
import com.android.setupwizardlib.util.FallbackThemeWrapper;
-
import java.util.HashMap;
import java.util.Map;
/**
- * A generic template class that inflates a template, provided in the constructor or in
- * {@code android:layout} through XML, and adds its children to a "container" in the template. When
+ * A generic template class that inflates a template, provided in the constructor or in {@code
+ * android:layout} through XML, and adds its children to a "container" in the template. When
* inflating this layout from XML, the {@code android:layout} and {@code suwContainer} attributes
* are required.
*/
public class TemplateLayout extends FrameLayout {
- /**
- * The container of the actual content. This will be a view in the template, which child views
- * will be added to when {@link #addView(View)} is called.
- */
- private ViewGroup mContainer;
-
- private Map<Class<? extends Mixin>, Mixin> mMixins = new HashMap<>();
+ /**
+ * The container of the actual content. This will be a view in the template, which child views
+ * will be added to when {@link #addView(View)} is called.
+ */
+ private ViewGroup container;
- public TemplateLayout(Context context, int template, int containerId) {
- super(context);
- init(template, containerId, null, R.attr.suwLayoutTheme);
- }
+ private final Map<Class<? extends Mixin>, Mixin> mixins = new HashMap<>();
- public TemplateLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(0, 0, attrs, R.attr.suwLayoutTheme);
- }
+ public TemplateLayout(Context context, int template, int containerId) {
+ super(context);
+ init(template, containerId, null, R.attr.suwLayoutTheme);
+ }
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public TemplateLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(0, 0, attrs, defStyleAttr);
- }
+ public TemplateLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(0, 0, attrs, R.attr.suwLayoutTheme);
+ }
- // All the constructors delegate to this init method. The 3-argument constructor is not
- // available in LinearLayout before v11, so call super with the exact same arguments.
- private void init(int template, int containerId, AttributeSet attrs, int defStyleAttr) {
- final TypedArray a = getContext().obtainStyledAttributes(attrs,
- R.styleable.SuwTemplateLayout, defStyleAttr, 0);
- if (template == 0) {
- template = a.getResourceId(R.styleable.SuwTemplateLayout_android_layout, 0);
- }
- if (containerId == 0) {
- containerId = a.getResourceId(R.styleable.SuwTemplateLayout_suwContainer, 0);
- }
- inflateTemplate(template, containerId);
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public TemplateLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(0, 0, attrs, defStyleAttr);
+ }
- a.recycle();
+ // All the constructors delegate to this init method. The 3-argument constructor is not
+ // available in LinearLayout before v11, so call super with the exact same arguments.
+ private void init(int template, int containerId, AttributeSet attrs, int defStyleAttr) {
+ final TypedArray a =
+ getContext().obtainStyledAttributes(attrs, R.styleable.SuwTemplateLayout, defStyleAttr, 0);
+ if (template == 0) {
+ template = a.getResourceId(R.styleable.SuwTemplateLayout_android_layout, 0);
}
-
- /**
- * Registers a mixin with a given class. This method should be called in the constructor.
- *
- * @param cls The class to register the mixin. In most cases, {@code cls} is the same as
- * {@code mixin.getClass()}, but {@code cls} can also be a super class of that. In
- * the latter case the the mixin must be retrieved using {@code cls} in
- * {@link #getMixin(Class)}, not the subclass.
- * @param mixin The mixin to be registered.
- * @param <M> The class of the mixin to register. This is the same as {@code cls}
- */
- protected <M extends Mixin> void registerMixin(Class<M> cls, M mixin) {
- mMixins.put(cls, mixin);
+ if (containerId == 0) {
+ containerId = a.getResourceId(R.styleable.SuwTemplateLayout_suwContainer, 0);
}
+ inflateTemplate(template, containerId);
- /**
- * Same as {@link android.view.View#findViewById(int)}, but may include views that are managed
- * by this view but not currently added to the view hierarchy. e.g. recycler view or list view
- * headers that are not currently shown.
- */
- // Returning generic type is the common pattern used for findViewBy* methods
- @SuppressWarnings("TypeParameterUnusedInFormals")
- public <T extends View> T findManagedViewById(int id) {
- return findViewById(id);
- }
+ a.recycle();
+ }
- /**
- * Get a {@link Mixin} from this template registered earlier in
- * {@link #registerMixin(Class, Mixin)}.
- *
- * @param cls The class marker of Mixin being requested. The actual Mixin returned may be a
- * subclass of this marker. Note that this must be the same class as registered in
- * {@link #registerMixin(Class, Mixin)}, which is not necessarily the
- * same as the concrete class of the instance returned by this method.
- * @param <M> The type of the class marker.
- * @return The mixin marked by {@code cls}, or null if the template does not have a matching
- * mixin.
- */
- @SuppressWarnings("unchecked")
- public <M extends Mixin> M getMixin(Class<M> cls) {
- return (M) mMixins.get(cls);
- }
+ /**
+ * Registers a mixin with a given class. This method should be called in the constructor.
+ *
+ * @param cls The class to register the mixin. In most cases, {@code cls} is the same as {@code
+ * mixin.getClass()}, but {@code cls} can also be a super class of that. In the latter case
+ * the mixin must be retrieved using {@code cls} in {@link #getMixin(Class)}, not the
+ * subclass.
+ * @param mixin The mixin to be registered.
+ * @param <M> The class of the mixin to register. This is the same as {@code cls}
+ */
+ protected <M extends Mixin> void registerMixin(Class<M> cls, M mixin) {
+ mixins.put(cls, mixin);
+ }
- @Override
- public void addView(View child, int index, ViewGroup.LayoutParams params) {
- mContainer.addView(child, index, params);
- }
+ /**
+ * Same as {@link android.view.View#findViewById(int)}, but may include views that are managed by
+ * this view but not currently added to the view hierarchy. e.g. recycler view or list view
+ * headers that are not currently shown.
+ */
+ // Returning generic type is the common pattern used for findViewBy* methods
+ @SuppressWarnings("TypeParameterUnusedInFormals")
+ public <T extends View> T findManagedViewById(int id) {
+ return findViewById(id);
+ }
- private void addViewInternal(View child) {
- super.addView(child, -1, generateDefaultLayoutParams());
- }
+ /**
+ * Get a {@link Mixin} from this template registered earlier in {@link #registerMixin(Class,
+ * Mixin)}.
+ *
+ * @param cls The class marker of Mixin being requested. The actual Mixin returned may be a
+ * subclass of this marker. Note that this must be the same class as registered in {@link
+ * #registerMixin(Class, Mixin)}, which is not necessarily the same as the concrete class of
+ * the instance returned by this method.
+ * @param <M> The type of the class marker.
+ * @return The mixin marked by {@code cls}, or null if the template does not have a matching
+ * mixin.
+ */
+ @SuppressWarnings("unchecked")
+ public <M extends Mixin> M getMixin(Class<M> cls) {
+ return (M) mixins.get(cls);
+ }
- private void inflateTemplate(int templateResource, int containerId) {
- final LayoutInflater inflater = LayoutInflater.from(getContext());
- final View templateRoot = onInflateTemplate(inflater, templateResource);
- addViewInternal(templateRoot);
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ container.addView(child, index, params);
+ }
- mContainer = findContainer(containerId);
- if (mContainer == null) {
- throw new IllegalArgumentException("Container cannot be null in TemplateLayout");
- }
- onTemplateInflated();
- }
+ private void addViewInternal(View child) {
+ super.addView(child, -1, generateDefaultLayoutParams());
+ }
- /**
- * This method inflates the template. Subclasses can override this method to customize the
- * template inflation, or change to a different default template. The root of the inflated
- * layout should be returned, and not added to the view hierarchy.
- *
- * @param inflater A LayoutInflater to inflate the template.
- * @param template The resource ID of the template to be inflated, or 0 if no template is
- * specified.
- * @return Root of the inflated layout.
- */
- protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) {
- return inflateTemplate(inflater, 0, template);
- }
+ private void inflateTemplate(int templateResource, int containerId) {
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ final View templateRoot = onInflateTemplate(inflater, templateResource);
+ addViewInternal(templateRoot);
- /**
- * Inflate the template using the given inflater and theme. The fallback theme will be applied
- * to the theme without overriding the values already defined in the theme, but simply providing
- * default values for values which have not been defined. This allows templates to add
- * additional required theme attributes without breaking existing clients.
- *
- * <p>In general, clients should still set the activity theme to the corresponding theme in
- * setup wizard lib, so that the content area gets the correct styles as well.
- *
- * @param inflater A LayoutInflater to inflate the template.
- * @param fallbackTheme A fallback theme to apply to the template. If the values defined in the
- * fallback theme is already defined in the original theme, the value in
- * the original theme takes precedence.
- * @param template The layout template to be inflated.
- * @return Root of the inflated layout.
- *
- * @see FallbackThemeWrapper
- */
- protected final View inflateTemplate(LayoutInflater inflater, @StyleRes int fallbackTheme,
- @LayoutRes int template) {
- if (template == 0) {
- throw new IllegalArgumentException("android:layout not specified for TemplateLayout");
- }
- if (fallbackTheme != 0) {
- inflater = LayoutInflater.from(
- new FallbackThemeWrapper(inflater.getContext(), fallbackTheme));
- }
- return inflater.inflate(template, this, false);
+ container = findContainer(containerId);
+ if (container == null) {
+ throw new IllegalArgumentException("Container cannot be null in TemplateLayout");
}
+ onTemplateInflated();
+ }
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- // Maintain compatibility with the deprecated way of specifying container ID.
- containerId = getContainerId();
- }
- return (ViewGroup) findViewById(containerId);
+ /**
+ * Inflate the template using the given inflater and theme. The fallback theme will be applied to
+ * the theme without overriding the values already defined in the theme, but simply providing
+ * default values for values which have not been defined. This allows templates to add additional
+ * required theme attributes without breaking existing clients.
+ *
+ * <p>In general, clients should still set the activity theme to the corresponding theme in setup
+ * wizard lib, so that the content area gets the correct styles as well.
+ *
+ * @param inflater A LayoutInflater to inflate the template.
+ * @param fallbackTheme A fallback theme to apply to the template. If the values defined in the
+ * fallback theme is already defined in the original theme, the value in the original theme
+ * takes precedence.
+ * @param template The layout template to be inflated.
+ * @return Root of the inflated layout.
+ * @see FallbackThemeWrapper
+ */
+ protected final View inflateTemplate(
+ LayoutInflater inflater, @StyleRes int fallbackTheme, @LayoutRes int template) {
+ if (template == 0) {
+ throw new IllegalArgumentException("android:layout not specified for TemplateLayout");
}
-
- /**
- * This is called after the template has been inflated and added to the view hierarchy.
- * Subclasses can implement this method to modify the template as necessary, such as caching
- * views retrieved from findViewById, or other view operations that need to be done in code.
- * You can think of this as {@link View#onFinishInflate()} but for inflation of the
- * template instead of for child views.
- */
- protected void onTemplateInflated() {
+ if (fallbackTheme != 0) {
+ inflater =
+ LayoutInflater.from(new FallbackThemeWrapper(inflater.getContext(), fallbackTheme));
}
+ return inflater.inflate(template, this, false);
+ }
+
+ /**
+ * This method inflates the template. Subclasses can override this method to customize the
+ * template inflation, or change to a different default template. The root of the inflated layout
+ * should be returned, and not added to the view hierarchy.
+ *
+ * @param inflater A LayoutInflater to inflate the template.
+ * @param template The resource ID of the template to be inflated, or 0 if no template is
+ * specified.
+ * @return Root of the inflated layout.
+ */
+ protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) {
+ return inflateTemplate(inflater, 0, template);
+ }
- /**
- * @return ID of the default container for this layout. This will be used to find the container
- * ViewGroup, which all children views of this layout will be placed in.
- * @deprecated Override {@link #findContainer(int)} instead.
- */
- @Deprecated
- protected int getContainerId() {
- return 0;
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ // Maintain compatibility with the deprecated way of specifying container ID.
+ containerId = getContainerId();
}
+ return (ViewGroup) findViewById(containerId);
+ }
- /* Animator support */
+ /**
+ * This is called after the template has been inflated and added to the view hierarchy. Subclasses
+ * can implement this method to modify the template as necessary, such as caching views retrieved
+ * from findViewById, or other view operations that need to be done in code. You can think of this
+ * as {@link View#onFinishInflate()} but for inflation of the template instead of for child views.
+ */
+ protected void onTemplateInflated() {}
- private float mXFraction;
- private ViewTreeObserver.OnPreDrawListener mPreDrawListener;
+ /**
+ * @return ID of the default container for this layout. This will be used to find the container
+ * ViewGroup, which all children views of this layout will be placed in.
+ * @deprecated Override {@link #findContainer(int)} instead.
+ */
+ @Deprecated
+ protected int getContainerId() {
+ return 0;
+ }
- /**
- * Set the X translation as a fraction of the width of this view. Make sure this method is not
- * stripped out by proguard when using this with {@link android.animation.ObjectAnimator}. You
- * may need to add
- * <code>
- * -keep @androidx.annotation.Keep class *
- * </code>
- * to your proguard configuration if you are seeing mysterious {@link NoSuchMethodError} at
- * runtime.
- */
- @Keep
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public void setXFraction(float fraction) {
- mXFraction = fraction;
- final int width = getWidth();
- if (width != 0) {
- setTranslationX(width * fraction);
- } else {
- // If we haven't done a layout pass yet, wait for one and then set the fraction before
- // the draw occurs using an OnPreDrawListener. Don't call translationX until we know
- // getWidth() has a reliable, non-zero value or else we will see the fragment flicker on
- // screen.
- if (mPreDrawListener == null) {
- mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
- setXFraction(mXFraction);
- return true;
- }
- };
- getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
- }
- }
- }
+ /* Animator support */
+
+ private float xFraction;
+ private ViewTreeObserver.OnPreDrawListener preDrawListener;
- /**
- * Return the X translation as a fraction of the width, as previously set in
- * {@link #setXFraction(float)}.
- *
- * @see #setXFraction(float)
- */
- @Keep
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public float getXFraction() {
- return mXFraction;
+ /**
+ * Set the X translation as a fraction of the width of this view. Make sure this method is not
+ * stripped out by proguard when using this with {@link android.animation.ObjectAnimator}. You may
+ * need to add <code>
+ * -keep @androidx.annotation.Keep class *
+ * </code> to your proguard configuration if you are seeing mysterious {@link NoSuchMethodError}
+ * at runtime.
+ */
+ @Keep
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public void setXFraction(float fraction) {
+ xFraction = fraction;
+ final int width = getWidth();
+ if (width != 0) {
+ setTranslationX(width * fraction);
+ } else {
+ // If we haven't done a layout pass yet, wait for one and then set the fraction before
+ // the draw occurs using an OnPreDrawListener. Don't call translationX until we know
+ // getWidth() has a reliable, non-zero value or else we will see the fragment flicker on
+ // screen.
+ if (preDrawListener == null) {
+ preDrawListener =
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
+ setXFraction(xFraction);
+ return true;
+ }
+ };
+ getViewTreeObserver().addOnPreDrawListener(preDrawListener);
+ }
}
+ }
+
+ /**
+ * Return the X translation as a fraction of the width, as previously set in {@link
+ * #setXFraction(float)}.
+ *
+ * @see #setXFraction(float)
+ */
+ @Keep
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public float getXFraction() {
+ return xFraction;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetector.java b/library/main/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetector.java
index f438691..2ea5288 100644
--- a/library/main/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetector.java
+++ b/library/main/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetector.java
@@ -24,95 +24,86 @@ import android.view.ViewConfiguration;
/**
* Helper class to detect the consective-tap gestures on a view.
*
- * <p/>This class is instantiated and used similar to a GestureDetector, where onTouchEvent should
- * be called when there are MotionEvents this detector should know about.
+ * <p>This class is instantiated and used similar to a GestureDetector, where onTouchEvent should be
+ * called when there are MotionEvents this detector should know about.
*/
public final class ConsecutiveTapsGestureDetector {
- public interface OnConsecutiveTapsListener {
- /**
- * Callback method when the user tapped on the target view X number of times.
- */
- void onConsecutiveTaps(int numOfConsecutiveTaps);
- }
-
- private final View mView;
- private final OnConsecutiveTapsListener mListener;
- private final int mConsecutiveTapTouchSlopSquare;
- private final int mConsecutiveTapTimeout;
+ public interface OnConsecutiveTapsListener {
+ /** Callback method when the user tapped on the target view X number of times. */
+ void onConsecutiveTaps(int numOfConsecutiveTaps);
+ }
- private int mConsecutiveTapsCounter = 0;
- private MotionEvent mPreviousTapEvent;
+ private final View view;
+ private final OnConsecutiveTapsListener listener;
+ private final int consecutiveTapTouchSlopSquare;
+ private final int consecutiveTapTimeout;
- /**
- * @param listener The listener that responds to the gesture.
- * @param view The target view that associated with consecutive-tap gesture.
- */
- public ConsecutiveTapsGestureDetector(
- OnConsecutiveTapsListener listener,
- View view) {
- mListener = listener;
- mView = view;
- int doubleTapSlop = ViewConfiguration.get(mView.getContext()).getScaledDoubleTapSlop();
- mConsecutiveTapTouchSlopSquare = doubleTapSlop * doubleTapSlop;
- mConsecutiveTapTimeout = ViewConfiguration.getDoubleTapTimeout();
- }
+ private int consecutiveTapsCounter = 0;
+ private MotionEvent previousTapEvent;
- /**
- * This method should be called from the relevant activity or view, typically in
- * onTouchEvent, onInterceptTouchEvent or dispatchTouchEvent.
- *
- * @param ev The motion event
- */
- public void onTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_UP) {
- Rect viewRect = new Rect();
- int[] leftTop = new int[2];
- mView.getLocationOnScreen(leftTop);
- viewRect.set(
- leftTop[0],
- leftTop[1],
- leftTop[0] + mView.getWidth(),
- leftTop[1] + mView.getHeight());
- if (viewRect.contains((int) ev.getX(), (int) ev.getY())) {
- if (isConsecutiveTap(ev)) {
- mConsecutiveTapsCounter++;
- } else {
- mConsecutiveTapsCounter = 1;
- }
- mListener.onConsecutiveTaps(mConsecutiveTapsCounter);
- } else {
- // Touch outside the target view. Reset counter.
- mConsecutiveTapsCounter = 0;
- }
+ /**
+ * @param listener The listener that responds to the gesture.
+ * @param view The target view that associated with consecutive-tap gesture.
+ */
+ public ConsecutiveTapsGestureDetector(OnConsecutiveTapsListener listener, View view) {
+ this.listener = listener;
+ this.view = view;
+ int doubleTapSlop = ViewConfiguration.get(this.view.getContext()).getScaledDoubleTapSlop();
+ consecutiveTapTouchSlopSquare = doubleTapSlop * doubleTapSlop;
+ consecutiveTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+ }
- if (mPreviousTapEvent != null) {
- mPreviousTapEvent.recycle();
- }
- mPreviousTapEvent = MotionEvent.obtain(ev);
+ /**
+ * This method should be called from the relevant activity or view, typically in onTouchEvent,
+ * onInterceptTouchEvent or dispatchTouchEvent.
+ *
+ * @param ev The motion event
+ */
+ public void onTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_UP) {
+ Rect viewRect = new Rect();
+ int[] leftTop = new int[2];
+ view.getLocationOnScreen(leftTop);
+ viewRect.set(
+ leftTop[0], leftTop[1], leftTop[0] + view.getWidth(), leftTop[1] + view.getHeight());
+ if (viewRect.contains((int) ev.getX(), (int) ev.getY())) {
+ if (isConsecutiveTap(ev)) {
+ consecutiveTapsCounter++;
+ } else {
+ consecutiveTapsCounter = 1;
}
- }
+ listener.onConsecutiveTaps(consecutiveTapsCounter);
+ } else {
+ // Touch outside the target view. Reset counter.
+ consecutiveTapsCounter = 0;
+ }
- /**
- * Resets the consecutive-tap counter to zero.
- */
- public void resetCounter() {
- mConsecutiveTapsCounter = 0;
+ if (previousTapEvent != null) {
+ previousTapEvent.recycle();
+ }
+ previousTapEvent = MotionEvent.obtain(ev);
}
+ }
- /**
- * Returns true if the distance between consecutive tap is within
- * {@link #mConsecutiveTapTouchSlopSquare}. False, otherwise.
- */
- private boolean isConsecutiveTap(MotionEvent currentTapEvent) {
- if (mPreviousTapEvent == null) {
- return false;
- }
+ /** Resets the consecutive-tap counter to zero. */
+ public void resetCounter() {
+ consecutiveTapsCounter = 0;
+ }
- double deltaX = mPreviousTapEvent.getX() - currentTapEvent.getX();
- double deltaY = mPreviousTapEvent.getY() - currentTapEvent.getY();
- long deltaTime = currentTapEvent.getEventTime() - mPreviousTapEvent.getEventTime();
- return (deltaX * deltaX + deltaY * deltaY <= mConsecutiveTapTouchSlopSquare)
- && deltaTime < mConsecutiveTapTimeout;
+ /**
+ * Returns true if the distance between consecutive tap is within {@link
+ * #consecutiveTapTouchSlopSquare}. False, otherwise.
+ */
+ private boolean isConsecutiveTap(MotionEvent currentTapEvent) {
+ if (previousTapEvent == null) {
+ return false;
}
+
+ double deltaX = previousTapEvent.getX() - currentTapEvent.getX();
+ double deltaY = previousTapEvent.getY() - currentTapEvent.getY();
+ long deltaTime = currentTapEvent.getEventTime() - previousTapEvent.getEventTime();
+ return (deltaX * deltaX + deltaY * deltaY <= consecutiveTapTouchSlopSquare)
+ && deltaTime < consecutiveTapTimeout;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/AbstractItem.java b/library/main/src/com/android/setupwizardlib/items/AbstractItem.java
index 11a9939..88f9294 100644
--- a/library/main/src/com/android/setupwizardlib/items/AbstractItem.java
+++ b/library/main/src/com/android/setupwizardlib/items/AbstractItem.java
@@ -25,42 +25,42 @@ import android.util.AttributeSet;
*/
public abstract class AbstractItem extends AbstractItemHierarchy implements IItem {
- public AbstractItem() {
- super();
- }
+ public AbstractItem() {
+ super();
+ }
- public AbstractItem(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
+ public AbstractItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
- @Override
- public int getCount() {
- return 1;
- }
+ @Override
+ public int getCount() {
+ return 1;
+ }
- @Override
- public IItem getItemAt(int position) {
- return this;
- }
+ @Override
+ public IItem getItemAt(int position) {
+ return this;
+ }
- @Override
- public ItemHierarchy findItemById(int id) {
- if (id == getId()) {
- return this;
- }
- return null;
+ @Override
+ public ItemHierarchy findItemById(int id) {
+ if (id == getId()) {
+ return this;
}
+ return null;
+ }
- /**
- * Convenience method to notify the adapter that the contents of this item has changed. This
- * only includes non-structural changes. Changes that causes the item to be removed should use
- * the other notification methods.
- *
- * @see #notifyItemRangeChanged(int, int)
- * @see #notifyItemRangeInserted(int, int)
- * @see #notifyItemRangeRemoved(int, int)
- */
- public void notifyItemChanged() {
- notifyItemRangeChanged(0, 1);
- }
+ /**
+ * Convenience method to notify the adapter that the contents of this item has changed. This only
+ * includes non-structural changes. Changes that causes the item to be removed should use the
+ * other notification methods.
+ *
+ * @see #notifyItemRangeChanged(int, int)
+ * @see #notifyItemRangeInserted(int, int)
+ * @see #notifyItemRangeRemoved(int, int)
+ */
+ public void notifyItemChanged() {
+ notifyItemRangeChanged(0, 1);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java b/library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java
index 805e7af..e33cc2f 100644
--- a/library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java
+++ b/library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java
@@ -20,138 +20,123 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
-
import com.android.setupwizardlib.R;
-
import java.util.ArrayList;
-/**
- * An abstract item hierarchy; provides default implementation for ID and observers.
- */
+/** An abstract item hierarchy; provides default implementation for ID and observers. */
public abstract class AbstractItemHierarchy implements ItemHierarchy {
- /* static section */
+ /* static section */
- private static final String TAG = "AbstractItemHierarchy";
+ private static final String TAG = "AbstractItemHierarchy";
- /* non-static section */
+ /* non-static section */
- private ArrayList<Observer> mObservers = new ArrayList<>();
- private int mId = 0;
+ private final ArrayList<Observer> observers = new ArrayList<>();
+ private int id = 0;
- public AbstractItemHierarchy() {
- }
+ public AbstractItemHierarchy() {}
- public AbstractItemHierarchy(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwAbstractItem);
- mId = a.getResourceId(R.styleable.SuwAbstractItem_android_id, 0);
- a.recycle();
- }
+ public AbstractItemHierarchy(Context context, AttributeSet attrs) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwAbstractItem);
+ id = a.getResourceId(R.styleable.SuwAbstractItem_android_id, 0);
+ a.recycle();
+ }
- public void setId(int id) {
- mId = id;
- }
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public int getViewId() {
+ return getId();
+ }
- public int getId() {
- return mId;
+ @Override
+ public void registerObserver(Observer observer) {
+ observers.add(observer);
+ }
+
+ @Override
+ public void unregisterObserver(Observer observer) {
+ observers.remove(observer);
+ }
+
+ /** @see Observer#onChanged(ItemHierarchy) */
+ public void notifyChanged() {
+ for (Observer observer : observers) {
+ observer.onChanged(this);
}
+ }
- public int getViewId() {
- return getId();
+ /** @see Observer#onItemRangeChanged(ItemHierarchy, int, int) */
+ public void notifyItemRangeChanged(int position, int itemCount) {
+ if (position < 0) {
+ Log.w(TAG, "notifyItemRangeChanged: Invalid position=" + position);
+ return;
+ }
+ if (itemCount < 0) {
+ Log.w(TAG, "notifyItemRangeChanged: Invalid itemCount=" + itemCount);
+ return;
}
- @Override
- public void registerObserver(Observer observer) {
- mObservers.add(observer);
+ for (Observer observer : observers) {
+ observer.onItemRangeChanged(this, position, itemCount);
}
+ }
- @Override
- public void unregisterObserver(Observer observer) {
- mObservers.remove(observer);
+ /** @see Observer#onItemRangeInserted(ItemHierarchy, int, int) */
+ public void notifyItemRangeInserted(int position, int itemCount) {
+ if (position < 0) {
+ Log.w(TAG, "notifyItemRangeInserted: Invalid position=" + position);
+ return;
+ }
+ if (itemCount < 0) {
+ Log.w(TAG, "notifyItemRangeInserted: Invalid itemCount=" + itemCount);
+ return;
}
- /**
- * @see Observer#onChanged(ItemHierarchy)
- */
- public void notifyChanged() {
- for (Observer observer : mObservers) {
- observer.onChanged(this);
- }
+ for (Observer observer : observers) {
+ observer.onItemRangeInserted(this, position, itemCount);
}
+ }
- /**
- * @see Observer#onItemRangeChanged(ItemHierarchy, int, int)
- */
- public void notifyItemRangeChanged(int position, int itemCount) {
- if (position < 0) {
- Log.w(TAG, "notifyItemRangeChanged: Invalid position=" + position);
- return;
- }
- if (itemCount < 0) {
- Log.w(TAG, "notifyItemRangeChanged: Invalid itemCount=" + itemCount);
- return;
- }
-
- for (Observer observer : mObservers) {
- observer.onItemRangeChanged(this, position, itemCount);
- }
+ /** @see Observer#onItemRangeMoved(ItemHierarchy, int, int, int) */
+ public void notifyItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ if (fromPosition < 0) {
+ Log.w(TAG, "notifyItemRangeMoved: Invalid fromPosition=" + fromPosition);
+ return;
+ }
+ if (toPosition < 0) {
+ Log.w(TAG, "notifyItemRangeMoved: Invalid toPosition=" + toPosition);
+ return;
+ }
+ if (itemCount < 0) {
+ Log.w(TAG, "notifyItemRangeMoved: Invalid itemCount=" + itemCount);
+ return;
}
- /**
- * @see Observer#onItemRangeInserted(ItemHierarchy, int, int)
- */
- public void notifyItemRangeInserted(int position, int itemCount) {
- if (position < 0) {
- Log.w(TAG, "notifyItemRangeInserted: Invalid position=" + position);
- return;
- }
- if (itemCount < 0) {
- Log.w(TAG, "notifyItemRangeInserted: Invalid itemCount=" + itemCount);
- return;
- }
-
- for (Observer observer : mObservers) {
- observer.onItemRangeInserted(this, position, itemCount);
- }
+ for (Observer observer : observers) {
+ observer.onItemRangeMoved(this, fromPosition, toPosition, itemCount);
}
+ }
- /**
- * @see Observer#onItemRangeMoved(ItemHierarchy, int, int, int)
- */
- public void notifyItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
- if (fromPosition < 0) {
- Log.w(TAG, "notifyItemRangeMoved: Invalid fromPosition=" + fromPosition);
- return;
- }
- if (toPosition < 0) {
- Log.w(TAG, "notifyItemRangeMoved: Invalid toPosition=" + toPosition);
- return;
- }
- if (itemCount < 0) {
- Log.w(TAG, "notifyItemRangeMoved: Invalid itemCount=" + itemCount);
- return;
- }
-
- for (Observer observer : mObservers) {
- observer.onItemRangeMoved(this, fromPosition, toPosition, itemCount);
- }
+ /** @see Observer#onItemRangeRemoved(ItemHierarchy, int, int) */
+ public void notifyItemRangeRemoved(int position, int itemCount) {
+ if (position < 0) {
+ Log.w(TAG, "notifyItemRangeInserted: Invalid position=" + position);
+ return;
+ }
+ if (itemCount < 0) {
+ Log.w(TAG, "notifyItemRangeInserted: Invalid itemCount=" + itemCount);
+ return;
}
- /**
- * @see Observer#onItemRangeRemoved(ItemHierarchy, int, int)
- */
- public void notifyItemRangeRemoved(int position, int itemCount) {
- if (position < 0) {
- Log.w(TAG, "notifyItemRangeInserted: Invalid position=" + position);
- return;
- }
- if (itemCount < 0) {
- Log.w(TAG, "notifyItemRangeInserted: Invalid itemCount=" + itemCount);
- return;
- }
-
- for (Observer observer : mObservers) {
- observer.onItemRangeRemoved(this, position, itemCount);
- }
+ for (Observer observer : observers) {
+ observer.onItemRangeRemoved(this, position, itemCount);
}
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/ButtonBarItem.java b/library/main/src/com/android/setupwizardlib/items/ButtonBarItem.java
index 06ce4ac..80b9453 100644
--- a/library/main/src/com/android/setupwizardlib/items/ButtonBarItem.java
+++ b/library/main/src/com/android/setupwizardlib/items/ButtonBarItem.java
@@ -21,16 +21,15 @@ import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
-
import com.android.setupwizardlib.R;
-
import java.util.ArrayList;
/**
- * A list item with one or more buttons, declared as
- * {@link com.android.setupwizardlib.items.ButtonItem}.
+ * A list item with one or more buttons, declared as {@link
+ * com.android.setupwizardlib.items.ButtonItem}.
*
* <p>Example usage:
+ *
* <pre>{@code
* &lt;ButtonBarItem&gt;
*
@@ -48,81 +47,81 @@ import java.util.ArrayList;
*/
public class ButtonBarItem extends AbstractItem implements ItemInflater.ItemParent {
- private final ArrayList<ButtonItem> mButtons = new ArrayList<>();
- private boolean mVisible = true;
-
- public ButtonBarItem() {
- super();
- }
-
- public ButtonBarItem(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public int getCount() {
- return isVisible() ? 1 : 0;
- }
-
- @Override
- public boolean isEnabled() {
- // The children buttons are enabled and clickable, but the item itself is not
- return false;
+ private final ArrayList<ButtonItem> buttons = new ArrayList<>();
+ private boolean visible = true;
+
+ public ButtonBarItem() {
+ super();
+ }
+
+ public ButtonBarItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public int getCount() {
+ return isVisible() ? 1 : 0;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ // The children buttons are enabled and clickable, but the item itself is not
+ return false;
+ }
+
+ @Override
+ public int getLayoutResource() {
+ return R.layout.suw_items_button_bar;
+ }
+
+ public void setVisible(boolean visible) {
+ this.visible = visible;
+ }
+
+ public boolean isVisible() {
+ return visible;
+ }
+
+ @Override
+ public int getViewId() {
+ return getId();
+ }
+
+ @Override
+ public void onBindView(View view) {
+ // Note: The efficiency could be improved by trying to recycle the buttons created by
+ // ButtonItem
+ final LinearLayout layout = (LinearLayout) view;
+ layout.removeAllViews();
+
+ for (ButtonItem buttonItem : buttons) {
+ Button button = buttonItem.createButton(layout);
+ layout.addView(button);
}
- @Override
- public int getLayoutResource() {
- return R.layout.suw_items_button_bar;
- }
-
- public void setVisible(boolean visible) {
- mVisible = visible;
- }
-
- public boolean isVisible() {
- return mVisible;
- }
+ view.setId(getViewId());
+ }
- @Override
- public int getViewId() {
- return getId();
+ @Override
+ public void addChild(ItemHierarchy child) {
+ if (child instanceof ButtonItem) {
+ buttons.add((ButtonItem) child);
+ } else {
+ throw new UnsupportedOperationException("Cannot add non-button item to Button Bar");
}
+ }
- @Override
- public void onBindView(View view) {
- // Note: The efficiency could be improved by trying to recycle the buttons created by
- // ButtonItem
- final LinearLayout layout = (LinearLayout) view;
- layout.removeAllViews();
-
- for (ButtonItem buttonItem : mButtons) {
- Button button = buttonItem.createButton(layout);
- layout.addView(button);
- }
-
- view.setId(getViewId());
+ @Override
+ public ItemHierarchy findItemById(int id) {
+ if (getId() == id) {
+ return this;
}
-
- @Override
- public void addChild(ItemHierarchy child) {
- if (child instanceof ButtonItem) {
- mButtons.add((ButtonItem) child);
- } else {
- throw new UnsupportedOperationException("Cannot add non-button item to Button Bar");
- }
- }
-
- @Override
- public ItemHierarchy findItemById(int id) {
- if (getId() == id) {
- return this;
- }
- for (ButtonItem button : mButtons) {
- final ItemHierarchy item = button.findItemById(id);
- if (item != null) {
- return item;
- }
- }
- return null;
+ for (ButtonItem button : buttons) {
+ final ItemHierarchy item = button.findItemById(id);
+ if (item != null) {
+ return item;
+ }
}
+ return null;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/ButtonItem.java b/library/main/src/com/android/setupwizardlib/items/ButtonItem.java
index 07802ae..b398f4d 100644
--- a/library/main/src/com/android/setupwizardlib/items/ButtonItem.java
+++ b/library/main/src/com/android/setupwizardlib/items/ButtonItem.java
@@ -25,7 +25,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-
import com.android.setupwizardlib.R;
/**
@@ -34,128 +33,123 @@ import com.android.setupwizardlib.R;
*/
public class ButtonItem extends AbstractItem implements View.OnClickListener {
- public interface OnClickListener {
- void onClick(ButtonItem item);
- }
-
- private boolean mEnabled = true;
- private CharSequence mText;
- private int mTheme = R.style.SuwButtonItem;
- private OnClickListener mListener;
-
- private Button mButton;
-
- public ButtonItem() {
- super();
- }
-
- public ButtonItem(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwButtonItem);
- mEnabled = a.getBoolean(R.styleable.SuwButtonItem_android_enabled, true);
- mText = a.getText(R.styleable.SuwButtonItem_android_text);
- mTheme = a.getResourceId(R.styleable.SuwButtonItem_android_theme, R.style.SuwButtonItem);
- a.recycle();
- }
-
- public void setOnClickListener(OnClickListener listener) {
- mListener = listener;
- }
-
- public void setText(CharSequence text) {
- mText = text;
- }
-
- public CharSequence getText() {
- return mText;
- }
-
- /**
- * The theme to use for this button. This can be used to create button of a particular style
- * (e.g. a colored or borderless button). Typically {@code android:buttonStyle} will be set in
- * the theme to change the style applied by the button.
- *
- * @param theme Resource ID of the theme
- */
- public void setTheme(int theme) {
- mTheme = theme;
- mButton = null;
- }
-
- /**
- * @return Resource ID of the theme used by this button.
- */
- public int getTheme() {
- return mTheme;
- }
-
- public void setEnabled(boolean enabled) {
- mEnabled = enabled;
- }
-
- @Override
- public int getCount() {
- return 0;
- }
-
- @Override
- public boolean isEnabled() {
- return mEnabled;
- }
-
- @Override
- public int getLayoutResource() {
- return 0;
- }
-
- /**
- * Do not use this since ButtonItem is not directly part of a list.
- */
- @Override
- public final void onBindView(View view) {
- throw new UnsupportedOperationException("Cannot bind to ButtonItem's view");
- }
-
- /**
- * Create a button according to this button item.
- *
- * @param parent The parent of the button, used to retrieve the theme and context for this
- * button.
- * @return A button that can be added to the parent.
- */
- protected Button createButton(ViewGroup parent) {
- if (mButton == null) {
- Context context = parent.getContext();
- if (mTheme != 0) {
- context = new ContextThemeWrapper(context, mTheme);
- }
- mButton = createButton(context);
- mButton.setOnClickListener(this);
- } else {
- if (mButton.getParent() instanceof ViewGroup) {
- // A view cannot be added to a different parent if one already exists. Remove this
- // button from its parent before returning.
- ((ViewGroup) mButton.getParent()).removeView(mButton);
- }
- }
- mButton.setEnabled(mEnabled);
- mButton.setText(mText);
- mButton.setId(getViewId());
- return mButton;
- }
-
- @Override
- public void onClick(View v) {
- if (mListener != null) {
- mListener.onClick(this);
- }
- }
-
- @SuppressLint("InflateParams") // This is used similar to Button(Context), so it's OK to not
- // specify the parent.
- private Button createButton(Context context) {
- // Inflate a single button from XML, so that when using support lib, it will take advantage
- // of the injected layout inflater and give us AppCompatButton instead.
- return (Button) LayoutInflater.from(context).inflate(R.layout.suw_button, null, false);
- }
+ public interface OnClickListener {
+ void onClick(ButtonItem item);
+ }
+
+ private boolean enabled = true;
+ private CharSequence text;
+ private int theme = R.style.SuwButtonItem;
+ private OnClickListener listener;
+
+ private Button button;
+
+ public ButtonItem() {
+ super();
+ }
+
+ public ButtonItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwButtonItem);
+ enabled = a.getBoolean(R.styleable.SuwButtonItem_android_enabled, true);
+ text = a.getText(R.styleable.SuwButtonItem_android_text);
+ theme = a.getResourceId(R.styleable.SuwButtonItem_android_theme, R.style.SuwButtonItem);
+ a.recycle();
+ }
+
+ public void setOnClickListener(OnClickListener listener) {
+ this.listener = listener;
+ }
+
+ public void setText(CharSequence text) {
+ this.text = text;
+ }
+
+ public CharSequence getText() {
+ return text;
+ }
+
+ /**
+ * The theme to use for this button. This can be used to create button of a particular style (e.g.
+ * a colored or borderless button). Typically {@code android:buttonStyle} will be set in the theme
+ * to change the style applied by the button.
+ *
+ * @param theme Resource ID of the theme
+ */
+ public void setTheme(int theme) {
+ this.theme = theme;
+ button = null;
+ }
+
+ /** @return Resource ID of the theme used by this button. */
+ public int getTheme() {
+ return theme;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @Override
+ public int getCount() {
+ return 0;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public int getLayoutResource() {
+ return 0;
+ }
+
+ /** Do not use this since ButtonItem is not directly part of a list. */
+ @Override
+ public final void onBindView(View view) {
+ throw new UnsupportedOperationException("Cannot bind to ButtonItem's view");
+ }
+
+ /**
+ * Create a button according to this button item.
+ *
+ * @param parent The parent of the button, used to retrieve the theme and context for this button.
+ * @return A button that can be added to the parent.
+ */
+ protected Button createButton(ViewGroup parent) {
+ if (button == null) {
+ Context context = parent.getContext();
+ if (theme != 0) {
+ context = new ContextThemeWrapper(context, theme);
+ }
+ button = createButton(context);
+ button.setOnClickListener(this);
+ } else {
+ if (button.getParent() instanceof ViewGroup) {
+ // A view cannot be added to a different parent if one already exists. Remove this
+ // button from its parent before returning.
+ ((ViewGroup) button.getParent()).removeView(button);
+ }
+ }
+ button.setEnabled(enabled);
+ button.setText(text);
+ button.setId(getViewId());
+ return button;
+ }
+
+ @SuppressLint("InflateParams") // This is used similar to Button(Context), so it's OK to not
+ // specify the parent.
+ private Button createButton(Context context) {
+ // Inflate a single button from XML, so that when using support lib, it will take advantage
+ // of the injected layout inflater and give us AppCompatButton instead.
+ return (Button) LayoutInflater.from(context).inflate(R.layout.suw_button, null, false);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (listener != null) {
+ listener.onClick(this);
+ }
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/IItem.java b/library/main/src/com/android/setupwizardlib/items/IItem.java
index 26391dc..cd29ec2 100644
--- a/library/main/src/com/android/setupwizardlib/items/IItem.java
+++ b/library/main/src/com/android/setupwizardlib/items/IItem.java
@@ -18,31 +18,27 @@ package com.android.setupwizardlib.items;
import android.view.View;
-/**
- * Representation of an item in an {@link ItemHierarchy}.
- */
+/** Representation of an item in an {@link ItemHierarchy}. */
public interface IItem {
- /**
- * Get the Android resource ID for locating the layout for this item.
- *
- * @return Resource ID for the layout of this item. This layout will be used to inflate the View
- * passed to {@link #onBindView(android.view.View)}.
- */
- int getLayoutResource();
+ /**
+ * Get the Android resource ID for locating the layout for this item.
+ *
+ * @return Resource ID for the layout of this item. This layout will be used to inflate the View
+ * passed to {@link #onBindView(android.view.View)}.
+ */
+ int getLayoutResource();
- /**
- * Called by items framework to display the data specified by this item. This method should
- * update {@code view} to reflect its data.
- *
- * @param view A view inflated from {@link #getLayoutResource()}, which should be updated to
- * display data from this item. This view may be recycled from other items with the
- * same layout resource.
- */
- void onBindView(View view);
+ /**
+ * Called by items framework to display the data specified by this item. This method should update
+ * {@code view} to reflect its data.
+ *
+ * @param view A view inflated from {@link #getLayoutResource()}, which should be updated to
+ * display data from this item. This view may be recycled from other items with the same
+ * layout resource.
+ */
+ void onBindView(View view);
- /**
- * @return True if this item is enabled.
- */
- boolean isEnabled();
+ /** @return True if this item is enabled. */
+ boolean isEnabled();
}
diff --git a/library/main/src/com/android/setupwizardlib/items/Item.java b/library/main/src/com/android/setupwizardlib/items/Item.java
index fc8823e..c0d49d3 100644
--- a/library/main/src/com/android/setupwizardlib/items/Item.java
+++ b/library/main/src/com/android/setupwizardlib/items/Item.java
@@ -23,7 +23,6 @@ import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
-
import com.android.setupwizardlib.R;
/**
@@ -32,146 +31,145 @@ import com.android.setupwizardlib.R;
*/
public class Item extends AbstractItem {
- private boolean mEnabled = true;
- private Drawable mIcon;
- private int mLayoutRes;
- private CharSequence mSummary;
- private CharSequence mTitle;
- private boolean mVisible = true;
-
- public Item() {
- super();
- mLayoutRes = getDefaultLayoutResource();
- }
-
- public Item(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwItem);
- mEnabled = a.getBoolean(R.styleable.SuwItem_android_enabled, true);
- mIcon = a.getDrawable(R.styleable.SuwItem_android_icon);
- mTitle = a.getText(R.styleable.SuwItem_android_title);
- mSummary = a.getText(R.styleable.SuwItem_android_summary);
- mLayoutRes = a.getResourceId(R.styleable.SuwItem_android_layout,
- getDefaultLayoutResource());
- mVisible = a.getBoolean(R.styleable.SuwItem_android_visible, true);
- a.recycle();
- }
-
- protected int getDefaultLayoutResource() {
- return R.layout.suw_items_default;
- }
-
- public void setEnabled(boolean enabled) {
- mEnabled = enabled;
- notifyItemChanged();
- }
-
- @Override
- public int getCount() {
- return isVisible() ? 1 : 0;
- }
-
- @Override
- public boolean isEnabled() {
- return mEnabled;
- }
-
- public void setIcon(Drawable icon) {
- mIcon = icon;
- notifyItemChanged();
- }
-
- public Drawable getIcon() {
- return mIcon;
- }
-
- public void setLayoutResource(int layoutResource) {
- mLayoutRes = layoutResource;
- notifyItemChanged();
- }
-
- @Override
- public int getLayoutResource() {
- return mLayoutRes;
- }
-
- public void setSummary(CharSequence summary) {
- mSummary = summary;
- notifyItemChanged();
- }
-
- public CharSequence getSummary() {
- return mSummary;
- }
-
- public void setTitle(CharSequence title) {
- mTitle = title;
- notifyItemChanged();
- }
-
- public CharSequence getTitle() {
- return mTitle;
- }
-
- public void setVisible(boolean visible) {
- if (mVisible == visible) {
- return;
- }
- mVisible = visible;
- if (!visible) {
- notifyItemRangeRemoved(0, 1);
- } else {
- notifyItemRangeInserted(0, 1);
- }
- }
-
- public boolean isVisible() {
- return mVisible;
- }
-
- @Override
- public int getViewId() {
- return getId();
- }
-
- @Override
- public void onBindView(View view) {
- TextView label = (TextView) view.findViewById(R.id.suw_items_title);
- label.setText(getTitle());
-
- TextView summaryView = (TextView) view.findViewById(R.id.suw_items_summary);
- CharSequence summary = getSummary();
- if (summary != null && summary.length() > 0) {
- summaryView.setText(summary);
- summaryView.setVisibility(View.VISIBLE);
- } else {
- summaryView.setVisibility(View.GONE);
- }
-
- final View iconContainer = view.findViewById(R.id.suw_items_icon_container);
- final Drawable icon = getIcon();
- if (icon != null) {
- final ImageView iconView = (ImageView) view.findViewById(R.id.suw_items_icon);
- // Set the image drawable to null before setting the state and level to avoid affecting
- // any recycled drawable in the ImageView
- iconView.setImageDrawable(null);
- onMergeIconStateAndLevels(iconView, icon);
- iconView.setImageDrawable(icon);
- iconContainer.setVisibility(View.VISIBLE);
- } else {
- iconContainer.setVisibility(View.GONE);
- }
-
- view.setId(getViewId());
- }
-
- /**
- * Copies state and level information from {@link #getIcon()} to the currently bound view's
- * ImageView. Subclasses can override this method to change whats being copied from the icon
- * to the ImageView.
- */
- protected void onMergeIconStateAndLevels(ImageView iconView, Drawable icon) {
- iconView.setImageState(icon.getState(), false /* merge */);
- iconView.setImageLevel(icon.getLevel());
- }
+ private boolean enabled = true;
+ private Drawable icon;
+ private int layoutRes;
+ private CharSequence summary;
+ private CharSequence title;
+ private boolean visible = true;
+
+ public Item() {
+ super();
+ layoutRes = getDefaultLayoutResource();
+ }
+
+ public Item(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwItem);
+ enabled = a.getBoolean(R.styleable.SuwItem_android_enabled, true);
+ icon = a.getDrawable(R.styleable.SuwItem_android_icon);
+ title = a.getText(R.styleable.SuwItem_android_title);
+ summary = a.getText(R.styleable.SuwItem_android_summary);
+ layoutRes = a.getResourceId(R.styleable.SuwItem_android_layout, getDefaultLayoutResource());
+ visible = a.getBoolean(R.styleable.SuwItem_android_visible, true);
+ a.recycle();
+ }
+
+ protected int getDefaultLayoutResource() {
+ return R.layout.suw_items_default;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ notifyItemChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return isVisible() ? 1 : 0;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setIcon(Drawable icon) {
+ this.icon = icon;
+ notifyItemChanged();
+ }
+
+ public Drawable getIcon() {
+ return icon;
+ }
+
+ public void setLayoutResource(int layoutResource) {
+ layoutRes = layoutResource;
+ notifyItemChanged();
+ }
+
+ @Override
+ public int getLayoutResource() {
+ return layoutRes;
+ }
+
+ public void setSummary(CharSequence summary) {
+ this.summary = summary;
+ notifyItemChanged();
+ }
+
+ public CharSequence getSummary() {
+ return summary;
+ }
+
+ public void setTitle(CharSequence title) {
+ this.title = title;
+ notifyItemChanged();
+ }
+
+ public CharSequence getTitle() {
+ return title;
+ }
+
+ public void setVisible(boolean visible) {
+ if (this.visible == visible) {
+ return;
+ }
+ this.visible = visible;
+ if (!visible) {
+ notifyItemRangeRemoved(0, 1);
+ } else {
+ notifyItemRangeInserted(0, 1);
+ }
+ }
+
+ public boolean isVisible() {
+ return visible;
+ }
+
+ @Override
+ public int getViewId() {
+ return getId();
+ }
+
+ @Override
+ public void onBindView(View view) {
+ TextView label = (TextView) view.findViewById(R.id.suw_items_title);
+ label.setText(getTitle());
+
+ TextView summaryView = (TextView) view.findViewById(R.id.suw_items_summary);
+ CharSequence summary = getSummary();
+ if (summary != null && summary.length() > 0) {
+ summaryView.setText(summary);
+ summaryView.setVisibility(View.VISIBLE);
+ } else {
+ summaryView.setVisibility(View.GONE);
+ }
+
+ final View iconContainer = view.findViewById(R.id.suw_items_icon_container);
+ final Drawable icon = getIcon();
+ if (icon != null) {
+ final ImageView iconView = (ImageView) view.findViewById(R.id.suw_items_icon);
+ // Set the image drawable to null before setting the state and level to avoid affecting
+ // any recycled drawable in the ImageView
+ iconView.setImageDrawable(null);
+ onMergeIconStateAndLevels(iconView, icon);
+ iconView.setImageDrawable(icon);
+ iconContainer.setVisibility(View.VISIBLE);
+ } else {
+ iconContainer.setVisibility(View.GONE);
+ }
+
+ view.setId(getViewId());
+ }
+
+ /**
+ * Copies state and level information from {@link #getIcon()} to the currently bound view's
+ * ImageView. Subclasses can override this method to change whats being copied from the icon to
+ * the ImageView.
+ */
+ protected void onMergeIconStateAndLevels(ImageView iconView, Drawable icon) {
+ iconView.setImageState(icon.getState(), false /* merge */);
+ iconView.setImageLevel(icon.getLevel());
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/ItemAdapter.java b/library/main/src/com/android/setupwizardlib/items/ItemAdapter.java
index 53285e7..851736c 100644
--- a/library/main/src/com/android/setupwizardlib/items/ItemAdapter.java
+++ b/library/main/src/com/android/setupwizardlib/items/ItemAdapter.java
@@ -23,130 +23,130 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
- * An adapter typically used with ListView to display an
- * {@link com.android.setupwizardlib.items.ItemHierarchy}. The item hierarchy used to create this
- * adapter can be inflated by {@link ItemInflater} from XML.
+ * An adapter typically used with ListView to display an {@link
+ * com.android.setupwizardlib.items.ItemHierarchy}. The item hierarchy used to create this adapter
+ * can be inflated by {@link ItemInflater} from XML.
*/
public class ItemAdapter extends BaseAdapter implements ItemHierarchy.Observer {
- private final ItemHierarchy mItemHierarchy;
- private ViewTypes mViewTypes = new ViewTypes();
-
- public ItemAdapter(ItemHierarchy hierarchy) {
- mItemHierarchy = hierarchy;
- mItemHierarchy.registerObserver(this);
- refreshViewTypes();
- }
-
- @Override
- public int getCount() {
- return mItemHierarchy.getCount();
- }
-
- @Override
- public IItem getItem(int position) {
- return mItemHierarchy.getItemAt(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public int getItemViewType(int position) {
- IItem item = getItem(position);
- int layoutRes = item.getLayoutResource();
- return mViewTypes.get(layoutRes);
- }
-
- @Override
- public int getViewTypeCount() {
- return mViewTypes.size();
- }
-
- private void refreshViewTypes() {
- for (int i = 0; i < getCount(); i++) {
- IItem item = getItem(i);
- mViewTypes.add(item.getLayoutResource());
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- IItem item = getItem(position);
- if (convertView == null) {
- LayoutInflater inflater = LayoutInflater.from(parent.getContext());
- convertView = inflater.inflate(item.getLayoutResource(), parent, false);
- }
- item.onBindView(convertView);
- return convertView;
- }
-
- @Override
- public void onChanged(ItemHierarchy hierarchy) {
- refreshViewTypes();
- notifyDataSetChanged();
- }
-
- @Override
- public void onItemRangeChanged(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- onChanged(itemHierarchy);
- }
-
- @Override
- public void onItemRangeInserted(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- onChanged(itemHierarchy);
- }
-
- @Override
- public void onItemRangeMoved(ItemHierarchy itemHierarchy, int fromPosition, int toPosition,
- int itemCount) {
- onChanged(itemHierarchy);
- }
-
- @Override
- public void onItemRangeRemoved(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- onChanged(itemHierarchy);
- }
-
- @Override
- public boolean isEnabled(int position) {
- return getItem(position).isEnabled();
- }
-
- public ItemHierarchy findItemById(int id) {
- return mItemHierarchy.findItemById(id);
- }
-
- public ItemHierarchy getRootItemHierarchy() {
- return mItemHierarchy;
- }
-
- /**
- * A helper class to pack a sparse set of integers (e.g. resource IDs) to a contiguous list of
- * integers (e.g. adapter positions), providing mapping to retrieve the original ID from a given
- * position. This is used to pack the view types of the adapter into contiguous integers from
- * a given layout resource.
- */
- private static class ViewTypes {
- private SparseIntArray mPositionMap = new SparseIntArray();
- private int nextPosition = 0;
-
- public int add(int id) {
- if (mPositionMap.indexOfKey(id) < 0) {
- mPositionMap.put(id, nextPosition);
- nextPosition++;
- }
- return mPositionMap.get(id);
- }
-
- public int size() {
- return mPositionMap.size();
- }
-
- public int get(int id) {
- return mPositionMap.get(id);
- }
- }
+ private final ItemHierarchy itemHierarchy;
+ private final ViewTypes viewTypes = new ViewTypes();
+
+ public ItemAdapter(ItemHierarchy hierarchy) {
+ itemHierarchy = hierarchy;
+ itemHierarchy.registerObserver(this);
+ refreshViewTypes();
+ }
+
+ @Override
+ public int getCount() {
+ return itemHierarchy.getCount();
+ }
+
+ @Override
+ public IItem getItem(int position) {
+ return itemHierarchy.getItemAt(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ IItem item = getItem(position);
+ int layoutRes = item.getLayoutResource();
+ return viewTypes.get(layoutRes);
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return viewTypes.size();
+ }
+
+ private void refreshViewTypes() {
+ for (int i = 0; i < getCount(); i++) {
+ IItem item = getItem(i);
+ viewTypes.add(item.getLayoutResource());
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ IItem item = getItem(position);
+ if (convertView == null) {
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ convertView = inflater.inflate(item.getLayoutResource(), parent, false);
+ }
+ item.onBindView(convertView);
+ return convertView;
+ }
+
+ @Override
+ public void onChanged(ItemHierarchy hierarchy) {
+ refreshViewTypes();
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onItemRangeChanged(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ onChanged(itemHierarchy);
+ }
+
+ @Override
+ public void onItemRangeInserted(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ onChanged(itemHierarchy);
+ }
+
+ @Override
+ public void onItemRangeMoved(
+ ItemHierarchy itemHierarchy, int fromPosition, int toPosition, int itemCount) {
+ onChanged(itemHierarchy);
+ }
+
+ @Override
+ public void onItemRangeRemoved(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ onChanged(itemHierarchy);
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItem(position).isEnabled();
+ }
+
+ public ItemHierarchy findItemById(int id) {
+ return itemHierarchy.findItemById(id);
+ }
+
+ public ItemHierarchy getRootItemHierarchy() {
+ return itemHierarchy;
+ }
+
+ /**
+ * A helper class to pack a sparse set of integers (e.g. resource IDs) to a contiguous list of
+ * integers (e.g. adapter positions), providing mapping to retrieve the original ID from a given
+ * position. This is used to pack the view types of the adapter into contiguous integers from a
+ * given layout resource.
+ */
+ private static class ViewTypes {
+ private final SparseIntArray positionMap = new SparseIntArray();
+ private int nextPosition = 0;
+
+ public int add(int id) {
+ if (positionMap.indexOfKey(id) < 0) {
+ positionMap.put(id, nextPosition);
+ nextPosition++;
+ }
+ return positionMap.get(id);
+ }
+
+ public int size() {
+ return positionMap.size();
+ }
+
+ public int get(int id) {
+ return positionMap.get(id);
+ }
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/ItemGroup.java b/library/main/src/com/android/setupwizardlib/items/ItemGroup.java
index 97b3199..246469f 100644
--- a/library/main/src/com/android/setupwizardlib/items/ItemGroup.java
+++ b/library/main/src/com/android/setupwizardlib/items/ItemGroup.java
@@ -20,301 +20,288 @@ import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseIntArray;
-
import java.util.ArrayList;
import java.util.List;
-public class ItemGroup extends AbstractItemHierarchy implements ItemInflater.ItemParent,
- ItemHierarchy.Observer {
-
- /* static section */
-
- private static final String TAG = "ItemGroup";
-
- /**
- * Binary search for the closest value that's smaller than or equal to {@code value}, and
- * return the corresponding key.
- */
- private static int binarySearch(SparseIntArray array, int value) {
- final int size = array.size();
- int lo = 0;
- int hi = size - 1;
-
- while (lo <= hi) {
- final int mid = (lo + hi) >>> 1;
- final int midVal = array.valueAt(mid);
-
- if (midVal < value) {
- lo = mid + 1;
- } else if (midVal > value) {
- hi = mid - 1;
- } else {
- return array.keyAt(mid); // value found
- }
- }
- // Value not found. Return the last item before our search range, which is the closest
- // value smaller than the value we are looking for.
- return array.keyAt(lo - 1);
+public class ItemGroup extends AbstractItemHierarchy
+ implements ItemInflater.ItemParent, ItemHierarchy.Observer {
+
+ /* static section */
+
+ private static final String TAG = "ItemGroup";
+
+ /**
+ * Binary search for the closest value that's smaller than or equal to {@code value}, and return
+ * the corresponding key.
+ */
+ private static int binarySearch(SparseIntArray array, int value) {
+ final int size = array.size();
+ int lo = 0;
+ int hi = size - 1;
+
+ while (lo <= hi) {
+ final int mid = (lo + hi) >>> 1;
+ final int midVal = array.valueAt(mid);
+
+ if (midVal < value) {
+ lo = mid + 1;
+ } else if (midVal > value) {
+ hi = mid - 1;
+ } else {
+ return array.keyAt(mid); // value found
+ }
}
-
- /**
- * Same as {@link List#indexOf(Object)}, but using identity comparison rather than
- * {@link Object#equals(Object)}.
- */
- private static <T> int identityIndexOf(List<T> list, T object) {
- final int count = list.size();
- for (int i = 0; i < count; i++) {
- if (list.get(i) == object) {
- return i;
- }
- }
- return -1;
+ // Value not found. Return the last item before our search range, which is the closest
+ // value smaller than the value we are looking for.
+ return array.keyAt(lo - 1);
+ }
+
+ /**
+ * Same as {@link List#indexOf(Object)}, but using identity comparison rather than {@link
+ * Object#equals(Object)}.
+ */
+ private static <T> int identityIndexOf(List<T> list, T object) {
+ final int count = list.size();
+ for (int i = 0; i < count; i++) {
+ if (list.get(i) == object) {
+ return i;
+ }
}
-
- /* non-static section */
-
- private List<ItemHierarchy> mChildren = new ArrayList<>();
-
- /**
- * A mapping from the index of an item hierarchy in mChildren, to the first position in which
- * the corresponding child hierarchy represents. For example:
- *
- * ItemHierarchy Item Item Position
- * Index
- *
- * 0 [ Wi-Fi AP 1 ] 0
- * | Wi-Fi AP 2 | 1
- * | Wi-Fi AP 3 | 2
- * | Wi-Fi AP 4 | 3
- * [ Wi-Fi AP 5 ] 4
- *
- * 1 [ <Empty Item Hierarchy> ]
- *
- * 2 [ Use cellular data ] 5
- *
- * 3 [ Don't connect ] 6
- *
- * For this example of Wi-Fi screen, the following mapping will be produced:
- * [ 0 -> 0 | 2 -> 5 | 3 -> 6 ]
- *
- * Also note how ItemHierarchy index 1 is not present in the map, because it is empty.
- *
- * ItemGroup uses this map to look for which ItemHierarchy an item at a given position belongs
- * to.
- */
- private SparseIntArray mHierarchyStart = new SparseIntArray();
-
- private int mCount = 0;
- private boolean mDirty = false;
-
- public ItemGroup() {
- super();
+ return -1;
+ }
+
+ /* non-static section */
+
+ private final List<ItemHierarchy> children = new ArrayList<>();
+
+ /**
+ * A mapping from the index of an item hierarchy in children, to the first position in which the
+ * corresponding child hierarchy represents. For example:
+ *
+ * <p>ItemHierarchy Item Item Position Index
+ *
+ * <p>0 [ Wi-Fi AP 1 ] 0 | Wi-Fi AP 2 | 1 | Wi-Fi AP 3 | 2 | Wi-Fi AP 4 | 3 [ Wi-Fi AP 5 ] 4
+ *
+ * <p>1 [ <Empty Item Hierarchy> ]
+ *
+ * <p>2 [ Use cellular data ] 5
+ *
+ * <p>3 [ Don't connect ] 6
+ *
+ * <p>For this example of Wi-Fi screen, the following mapping will be produced: [ 0 -> 0 | 2 -> 5
+ * | 3 -> 6 ]
+ *
+ * <p>Also note how ItemHierarchy index 1 is not present in the map, because it is empty.
+ *
+ * <p>ItemGroup uses this map to look for which ItemHierarchy an item at a given position belongs
+ * to.
+ */
+ private final SparseIntArray hierarchyStart = new SparseIntArray();
+
+ private int count = 0;
+ private boolean dirty = false;
+
+ public ItemGroup() {
+ super();
+ }
+
+ public ItemGroup(Context context, AttributeSet attrs) {
+ // Constructor for XML inflation
+ super(context, attrs);
+ }
+
+ /** Add a child hierarchy to this item group. */
+ @Override
+ public void addChild(ItemHierarchy child) {
+ dirty = true;
+ children.add(child);
+ child.registerObserver(this);
+
+ final int count = child.getCount();
+ if (count > 0) {
+ notifyItemRangeInserted(getChildPosition(child), count);
}
-
- public ItemGroup(Context context, AttributeSet attrs) {
- // Constructor for XML inflation
- super(context, attrs);
- }
-
- /**
- * Add a child hierarchy to this item group.
- */
- @Override
- public void addChild(ItemHierarchy child) {
- mDirty = true;
- mChildren.add(child);
- child.registerObserver(this);
-
- final int count = child.getCount();
- if (count > 0) {
- notifyItemRangeInserted(getChildPosition(child), count);
- }
+ }
+
+ /**
+ * Remove a previously added child from this item group.
+ *
+ * @return True if there is a match for the child and it is removed. False if the child could not
+ * be found in our list of child hierarchies.
+ */
+ public boolean removeChild(ItemHierarchy child) {
+ final int childIndex = identityIndexOf(children, child);
+ final int childPosition = getChildPosition(childIndex);
+ dirty = true;
+ if (childIndex != -1) {
+ final int childCount = child.getCount();
+ children.remove(childIndex);
+ child.unregisterObserver(this);
+ if (childCount > 0) {
+ notifyItemRangeRemoved(childPosition, childCount);
+ }
+ return true;
}
+ return false;
+ }
- /**
- * Remove a previously added child from this item group.
- *
- * @return True if there is a match for the child and it is removed. False if the child could
- * not be found in our list of child hierarchies.
- */
- public boolean removeChild(ItemHierarchy child) {
- final int childIndex = identityIndexOf(mChildren, child);
- final int childPosition = getChildPosition(childIndex);
- mDirty = true;
- if (childIndex != -1) {
- final int childCount = child.getCount();
- mChildren.remove(childIndex);
- child.unregisterObserver(this);
- if (childCount > 0) {
- notifyItemRangeRemoved(childPosition, childCount);
- }
- return true;
- }
- return false;
+ /** Remove all children from this hierarchy. */
+ public void clear() {
+ if (children.isEmpty()) {
+ return;
}
- /**
- * Remove all children from this hierarchy.
- */
- public void clear() {
- if (mChildren.size() == 0) {
- return;
- }
-
- final int numRemoved = getCount();
+ final int numRemoved = getCount();
- for (ItemHierarchy item : mChildren) {
- item.unregisterObserver(this);
- }
- mDirty = true;
- mChildren.clear();
- notifyItemRangeRemoved(0, numRemoved);
+ for (ItemHierarchy item : children) {
+ item.unregisterObserver(this);
}
-
- @Override
- public int getCount() {
- updateDataIfNeeded();
- return mCount;
+ dirty = true;
+ children.clear();
+ notifyItemRangeRemoved(0, numRemoved);
+ }
+
+ @Override
+ public int getCount() {
+ updateDataIfNeeded();
+ return count;
+ }
+
+ @Override
+ public IItem getItemAt(int position) {
+ int itemIndex = getItemIndex(position);
+ ItemHierarchy item = children.get(itemIndex);
+ int subpos = position - hierarchyStart.get(itemIndex);
+ return item.getItemAt(subpos);
+ }
+
+ @Override
+ public void onChanged(ItemHierarchy hierarchy) {
+ // Need to set dirty, because our children may have gotten more items.
+ dirty = true;
+ notifyChanged();
+ }
+
+ /**
+ * @return The "Item Position" of the given child, or -1 if the child is not found. If the given
+ * child is empty, position of the next visible item is returned.
+ */
+ private int getChildPosition(ItemHierarchy child) {
+ // Check the identity of the child rather than using .equals(), because here we want
+ // to find the index of the instance itself rather than something that equals to it.
+ return getChildPosition(identityIndexOf(children, child));
+ }
+
+ private int getChildPosition(int childIndex) {
+ updateDataIfNeeded();
+ if (childIndex != -1) {
+ int childPos = -1;
+ int childCount = children.size();
+ for (int i = childIndex; childPos < 0 && i < childCount; i++) {
+ // Find the position of the first visible child after childIndex. This is required
+ // when removing the last item from a nested ItemGroup.
+ childPos = hierarchyStart.get(i, -1);
+ }
+ if (childPos < 0) {
+ // If the last item in a group is being removed, there will be no visible item.
+ // In that case return the count instead, since that is where the item would have
+ // been if the child is not empty.
+ childPos = getCount();
+ }
+ return childPos;
}
-
- @Override
- public IItem getItemAt(int position) {
- int itemIndex = getItemIndex(position);
- ItemHierarchy item = mChildren.get(itemIndex);
- int subpos = position - mHierarchyStart.get(itemIndex);
- return item.getItemAt(subpos);
+ return -1;
+ }
+
+ @Override
+ public void onItemRangeChanged(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ // No need to set dirty because onItemRangeChanged does not include any structural changes.
+ final int childPosition = getChildPosition(itemHierarchy);
+ if (childPosition >= 0) {
+ notifyItemRangeChanged(childPosition + positionStart, itemCount);
+ } else {
+ Log.e(TAG, "Unexpected child change " + itemHierarchy);
}
-
- @Override
- public void onChanged(ItemHierarchy hierarchy) {
- // Need to set dirty, because our children may have gotten more items.
- mDirty = true;
- notifyChanged();
+ }
+
+ @Override
+ public void onItemRangeInserted(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ dirty = true;
+ final int childPosition = getChildPosition(itemHierarchy);
+ if (childPosition >= 0) {
+ notifyItemRangeInserted(childPosition + positionStart, itemCount);
+ } else {
+ Log.e(TAG, "Unexpected child insert " + itemHierarchy);
}
-
- /**
- * @return The "Item Position" of the given child, or -1 if the child is not found. If the given
- * child is empty, position of the next visible item is returned.
- */
- private int getChildPosition(ItemHierarchy child) {
- // Check the identity of the child rather than using .equals(), because here we want
- // to find the index of the instance itself rather than something that equals to it.
- return getChildPosition(identityIndexOf(mChildren, child));
+ }
+
+ @Override
+ public void onItemRangeMoved(
+ ItemHierarchy itemHierarchy, int fromPosition, int toPosition, int itemCount) {
+ dirty = true;
+ final int childPosition = getChildPosition(itemHierarchy);
+ if (childPosition >= 0) {
+ notifyItemRangeMoved(childPosition + fromPosition, childPosition + toPosition, itemCount);
+ } else {
+ Log.e(TAG, "Unexpected child move " + itemHierarchy);
}
-
- private int getChildPosition(int childIndex) {
- updateDataIfNeeded();
- if (childIndex != -1) {
- int childPos = -1;
- int childCount = mChildren.size();
- for (int i = childIndex; childPos < 0 && i < childCount; i++) {
- // Find the position of the first visible child after childIndex. This is required
- // when removing the last item from a nested ItemGroup.
- childPos = mHierarchyStart.get(i, -1);
- }
- if (childPos < 0) {
- // If the last item in a group is being removed, there will be no visible item.
- // In that case return the count instead, since that is where the item would have
- // been if the child is not empty.
- childPos = getCount();
- }
- return childPos;
- }
- return -1;
+ }
+
+ @Override
+ public void onItemRangeRemoved(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ dirty = true;
+ final int childPosition = getChildPosition(itemHierarchy);
+ if (childPosition >= 0) {
+ notifyItemRangeRemoved(childPosition + positionStart, itemCount);
+ } else {
+ Log.e(TAG, "Unexpected child remove " + itemHierarchy);
}
+ }
- @Override
- public void onItemRangeChanged(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- // No need to set dirty because onItemRangeChanged does not include any structural changes.
- final int childPosition = getChildPosition(itemHierarchy);
- if (childPosition >= 0) {
- notifyItemRangeChanged(childPosition + positionStart, itemCount);
- } else {
- Log.e(TAG, "Unexpected child change " + itemHierarchy);
- }
+ @Override
+ public ItemHierarchy findItemById(int id) {
+ if (id == getId()) {
+ return this;
}
-
- @Override
- public void onItemRangeInserted(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- mDirty = true;
- final int childPosition = getChildPosition(itemHierarchy);
- if (childPosition >= 0) {
- notifyItemRangeInserted(childPosition + positionStart, itemCount);
- } else {
- Log.e(TAG, "Unexpected child insert " + itemHierarchy);
- }
+ for (ItemHierarchy child : children) {
+ ItemHierarchy childFindItem = child.findItemById(id);
+ if (childFindItem != null) {
+ return childFindItem;
+ }
}
-
- @Override
- public void onItemRangeMoved(ItemHierarchy itemHierarchy, int fromPosition, int toPosition,
- int itemCount) {
- mDirty = true;
- final int childPosition = getChildPosition(itemHierarchy);
- if (childPosition >= 0) {
- notifyItemRangeMoved(childPosition + fromPosition, childPosition + toPosition,
- itemCount);
- } else {
- Log.e(TAG, "Unexpected child move " + itemHierarchy);
+ return null;
+ }
+
+ /** If dirty, this method will recalculate the number of items and hierarchyStart. */
+ private void updateDataIfNeeded() {
+ if (dirty) {
+ count = 0;
+ hierarchyStart.clear();
+ for (int itemIndex = 0; itemIndex < children.size(); itemIndex++) {
+ ItemHierarchy item = children.get(itemIndex);
+ if (item.getCount() > 0) {
+ hierarchyStart.put(itemIndex, count);
}
+ count += item.getCount();
+ }
+ dirty = false;
}
-
- @Override
- public void onItemRangeRemoved(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- mDirty = true;
- final int childPosition = getChildPosition(itemHierarchy);
- if (childPosition >= 0) {
- notifyItemRangeRemoved(childPosition + positionStart, itemCount);
- } else {
- Log.e(TAG, "Unexpected child remove " + itemHierarchy);
- }
+ }
+
+ /**
+ * Use binary search to locate the item hierarchy a position is contained in.
+ *
+ * @return Index of the item hierarchy which is responsible for the item at {@code position}.
+ */
+ private int getItemIndex(int position) {
+ updateDataIfNeeded();
+ if (position < 0 || position >= count) {
+ throw new IndexOutOfBoundsException("size=" + count + "; index=" + position);
}
-
- @Override
- public ItemHierarchy findItemById(int id) {
- if (id == getId()) {
- return this;
- }
- for (ItemHierarchy child : mChildren) {
- ItemHierarchy childFindItem = child.findItemById(id);
- if (childFindItem != null) {
- return childFindItem;
- }
- }
- return null;
- }
-
- /**
- * If dirty, this method will recalculate the number of items and mHierarchyStart.
- */
- private void updateDataIfNeeded() {
- if (mDirty) {
- mCount = 0;
- mHierarchyStart.clear();
- for (int itemIndex = 0; itemIndex < mChildren.size(); itemIndex++) {
- ItemHierarchy item = mChildren.get(itemIndex);
- if (item.getCount() > 0) {
- mHierarchyStart.put(itemIndex, mCount);
- }
- mCount += item.getCount();
- }
- mDirty = false;
- }
- }
-
- /**
- * Use binary search to locate the item hierarchy a position is contained in.
- *
- * @return Index of the item hierarchy which is responsible for the item at {@code position}.
- */
- private int getItemIndex(int position) {
- updateDataIfNeeded();
- if (position < 0 || position >= mCount) {
- throw new IndexOutOfBoundsException("size=" + mCount + "; index=" + position);
- }
- int result = binarySearch(mHierarchyStart, position);
- if (result < 0) {
- throw new IllegalStateException("Cannot have item start index < 0");
- }
- return result;
+ int result = binarySearch(hierarchyStart, position);
+ if (result < 0) {
+ throw new IllegalStateException("Cannot have item start index < 0");
}
+ return result;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java b/library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java
index 627b6f0..85e0870 100644
--- a/library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java
+++ b/library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java
@@ -20,82 +20,69 @@ package com.android.setupwizardlib.items;
* Representation of zero or more items in a list. Each instance of ItemHierarchy should be capable
* of being wrapped in ItemAdapter and be displayed.
*
- * For example, {@link com.android.setupwizardlib.items.Item} is a representation of a single item,
- * typically with data provided from XML. {@link com.android.setupwizardlib.items.ItemGroup}
+ * <p>For example, {@link com.android.setupwizardlib.items.Item} is a representation of a single
+ * item, typically with data provided from XML. {@link com.android.setupwizardlib.items.ItemGroup}
* represents a list of child item hierarchies it contains, but itself does not do any display.
*/
public interface ItemHierarchy {
+ /**
+ * Observer for any changes in this hierarchy. If anything updated that causes this hierarchy to
+ * show different content, this observer should be called.
+ */
+ interface Observer {
/**
- * Observer for any changes in this hierarchy. If anything updated that causes this hierarchy to
- * show different content, this observer should be called.
+ * Called when an underlying data update that can cause this hierarchy to show different content
+ * has occurred.
+ *
+ * <p>Note: This is a catch-all notification, but recycler view will have a harder time figuring
+ * out the animations for the change, and might even not animate the change at all.
*/
- interface Observer {
- /**
- * Called when an underlying data update that can cause this hierarchy to show different
- * content has occurred.
- *
- * <p>Note: This is a catch-all notification, but recycler view will have a harder time
- * figuring out the animations for the change, and might even not animate the change at all.
- */
- void onChanged(ItemHierarchy itemHierarchy);
+ void onChanged(ItemHierarchy itemHierarchy);
- /**
- * Called when an underlying data update that can cause changes that are local to the given
- * items. This method indicates that there are no structural changes like inserting or
- * removing items.
- */
- void onItemRangeChanged(ItemHierarchy itemHierarchy, int positionStart, int itemCount);
+ /**
+ * Called when an underlying data update that can cause changes that are local to the given
+ * items. This method indicates that there are no structural changes like inserting or removing
+ * items.
+ */
+ void onItemRangeChanged(ItemHierarchy itemHierarchy, int positionStart, int itemCount);
- /**
- * Called when items are inserted at the given position.
- */
- void onItemRangeInserted(ItemHierarchy itemHierarchy, int positionStart, int itemCount);
+ /** Called when items are inserted at the given position. */
+ void onItemRangeInserted(ItemHierarchy itemHierarchy, int positionStart, int itemCount);
- /**
- * Called when the given items are moved to a different position.
- */
- void onItemRangeMoved(ItemHierarchy itemHierarchy, int fromPosition, int toPosition,
- int itemCount);
+ /** Called when the given items are moved to a different position. */
+ void onItemRangeMoved(
+ ItemHierarchy itemHierarchy, int fromPosition, int toPosition, int itemCount);
- /**
- * Called when the given items are removed from the item hierarchy.
- */
- void onItemRangeRemoved(ItemHierarchy itemHierarchy, int positionStart, int itemCount);
- }
+ /** Called when the given items are removed from the item hierarchy. */
+ void onItemRangeRemoved(ItemHierarchy itemHierarchy, int positionStart, int itemCount);
+ }
- /**
- * Register an observer to observe changes for this item hierarchy.
- */
- void registerObserver(Observer observer);
+ /** Register an observer to observe changes for this item hierarchy. */
+ void registerObserver(Observer observer);
- /**
- * Unregister a previously registered observer.
- */
- void unregisterObserver(Observer observer);
+ /** Unregister a previously registered observer. */
+ void unregisterObserver(Observer observer);
- /**
- * @return the number of items this item hierarchy represent.
- */
- int getCount();
+ /** @return the number of items this item hierarchy represent. */
+ int getCount();
- /**
- * Get the item at position.
- *
- * @param position An integer from 0 to {@link #getCount()}}, which indicates the position in
- * this item hierarchy to get the child item.
- * @return A representation of the item at {@code position}. Must not be {@code null}.
- */
- IItem getItemAt(int position);
+ /**
+ * Get the item at position.
+ *
+ * @param position An integer from 0 to {@link #getCount()}}, which indicates the position in this
+ * item hierarchy to get the child item.
+ * @return A representation of the item at {@code position}. Must not be {@code null}.
+ */
+ IItem getItemAt(int position);
- /**
- * Find an item hierarchy within this hierarchy which has the given ID. Or null if no match is
- * found. This hierarchy will be returned if our ID matches. Same restrictions for Android
- * resource IDs apply to this ID. In fact, typically this ID is a resource ID generated from
- * XML.
- *
- * @param id An ID to search for in this item hierarchy.
- * @return An ItemHierarchy which matches the given ID.
- */
- ItemHierarchy findItemById(int id);
+ /**
+ * Find an item hierarchy within this hierarchy which has the given ID. Or null if no match is
+ * found. This hierarchy will be returned if our ID matches. Same restrictions for Android
+ * resource IDs apply to this ID. In fact, typically this ID is a resource ID generated from XML.
+ *
+ * @param id An ID to search for in this item hierarchy.
+ * @return An ItemHierarchy which matches the given ID.
+ */
+ ItemHierarchy findItemById(int id);
}
diff --git a/library/main/src/com/android/setupwizardlib/items/ItemInflater.java b/library/main/src/com/android/setupwizardlib/items/ItemInflater.java
index 618d785..26cdbbd 100644
--- a/library/main/src/com/android/setupwizardlib/items/ItemInflater.java
+++ b/library/main/src/com/android/setupwizardlib/items/ItemInflater.java
@@ -18,26 +18,24 @@ package com.android.setupwizardlib.items;
import android.content.Context;
-/**
- * Inflate {@link Item} hierarchies from XML files.
- */
+/** Inflate {@link Item} hierarchies from XML files. */
public class ItemInflater extends ReflectionInflater<ItemHierarchy> {
- public interface ItemParent {
- void addChild(ItemHierarchy child);
- }
+ public interface ItemParent {
+ void addChild(ItemHierarchy child);
+ }
- public ItemInflater(Context context) {
- super(context);
- setDefaultPackage(Item.class.getPackage().getName() + ".");
- }
+ public ItemInflater(Context context) {
+ super(context);
+ setDefaultPackage(Item.class.getPackage().getName() + ".");
+ }
- @Override
- protected void onAddChildItem(ItemHierarchy parent, ItemHierarchy child) {
- if (parent instanceof ItemParent) {
- ((ItemParent) parent).addChild(child);
- } else {
- throw new IllegalArgumentException("Cannot add child item to " + parent);
- }
+ @Override
+ protected void onAddChildItem(ItemHierarchy parent, ItemHierarchy child) {
+ if (parent instanceof ItemParent) {
+ ((ItemParent) parent).addChild(child);
+ } else {
+ throw new IllegalArgumentException("Cannot add child item to " + parent);
}
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/ReflectionInflater.java b/library/main/src/com/android/setupwizardlib/items/ReflectionInflater.java
index 8ffa943..3382f56 100644
--- a/library/main/src/com/android/setupwizardlib/items/ReflectionInflater.java
+++ b/library/main/src/com/android/setupwizardlib/items/ReflectionInflater.java
@@ -17,12 +17,10 @@
package com.android.setupwizardlib.items;
import android.content.Context;
-import android.util.AttributeSet;
-import android.view.InflateException;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
+import android.util.AttributeSet;
+import android.view.InflateException;
import java.lang.reflect.Constructor;
import java.util.HashMap;
@@ -38,107 +36,104 @@ import java.util.HashMap;
*/
public abstract class ReflectionInflater<T> extends SimpleInflater<T> {
- /* static section */
-
- private static final Class<?>[] CONSTRUCTOR_SIGNATURE =
- new Class<?>[] {Context.class, AttributeSet.class};
-
- private static final HashMap<String, Constructor<?>> sConstructorMap = new HashMap<>();
-
- /* non-static section */
-
- // Array used to contain the constructor arguments (Context, AttributeSet), to avoid allocating
- // a new array for creation of every item.
- private final Object[] mTempConstructorArgs = new Object[2];
-
- @Nullable
- private String mDefaultPackage;
-
- @NonNull
- private final Context mContext;
-
- /**
- * Create a new inflater instance associated with a particular Context.
- *
- * @param context The context used to resolve resource IDs. This context is also passed to the
- * constructor of the items created as the first argument.
- */
- protected ReflectionInflater(@NonNull Context context) {
- super(context.getResources());
- mContext = context;
+ /* static section */
+
+ private static final Class<?>[] CONSTRUCTOR_SIGNATURE =
+ new Class<?>[] {Context.class, AttributeSet.class};
+
+ private static final HashMap<String, Constructor<?>> constructorMap = new HashMap<>();
+
+ /* non-static section */
+
+ // Array used to contain the constructor arguments (Context, AttributeSet), to avoid allocating
+ // a new array for creation of every item.
+ private final Object[] tempConstructorArgs = new Object[2];
+
+ @Nullable private String defaultPackage;
+
+ @NonNull private final Context context;
+
+ /**
+ * Create a new inflater instance associated with a particular Context.
+ *
+ * @param context The context used to resolve resource IDs. This context is also passed to the
+ * constructor of the items created as the first argument.
+ */
+ protected ReflectionInflater(@NonNull Context context) {
+ super(context.getResources());
+ this.context = context;
+ }
+
+ @NonNull
+ public Context getContext() {
+ return context;
+ }
+
+ /**
+ * Instantiate the class by name. This attempts to instantiate class of the given {@code name}
+ * found in this inflater's ClassLoader.
+ *
+ * @param tagName The full name of the class to be instantiated.
+ * @param attrs The XML attributes supplied for this instance.
+ * @return The newly instantiated item.
+ */
+ @NonNull
+ public final T createItem(String tagName, String prefix, AttributeSet attrs) {
+ String qualifiedName = tagName;
+ if (prefix != null && qualifiedName.indexOf('.') == -1) {
+ qualifiedName = prefix.concat(qualifiedName);
}
+ @SuppressWarnings("unchecked") // qualifiedName should correspond to a subclass of T
+ Constructor<? extends T> constructor =
+ (Constructor<? extends T>) constructorMap.get(qualifiedName);
- @NonNull
- public Context getContext() {
- return mContext;
- }
-
- /**
- * Instantiate the class by name. This attempts to instantiate class of the given {@code name}
- * found in this inflater's ClassLoader.
- *
- * @param tagName The full name of the class to be instantiated.
- * @param attrs The XML attributes supplied for this instance.
- *
- * @return The newly instantiated item.
- */
- @NonNull
- public final T createItem(String tagName, String prefix, AttributeSet attrs) {
- String qualifiedName = tagName;
- if (prefix != null && qualifiedName.indexOf('.') == -1) {
- qualifiedName = prefix.concat(qualifiedName);
- }
+ try {
+ if (constructor == null) {
+ // Class not found in the cache, see if it's real, and try to add it
@SuppressWarnings("unchecked") // qualifiedName should correspond to a subclass of T
- Constructor<? extends T> constructor =
- (Constructor<? extends T>) sConstructorMap.get(qualifiedName);
-
- try {
- if (constructor == null) {
- // Class not found in the cache, see if it's real, and try to add it
- @SuppressWarnings("unchecked") // qualifiedName should correspond to a subclass of T
- Class<? extends T> clazz =
- (Class<? extends T>) mContext.getClassLoader().loadClass(qualifiedName);
- constructor = clazz.getConstructor(CONSTRUCTOR_SIGNATURE);
- constructor.setAccessible(true);
- sConstructorMap.put(tagName, constructor);
- }
-
- mTempConstructorArgs[0] = mContext;
- mTempConstructorArgs[1] = attrs;
- final T item = constructor.newInstance(mTempConstructorArgs);
- mTempConstructorArgs[0] = null;
- mTempConstructorArgs[1] = null;
- return item;
- } catch (Exception e) {
- throw new InflateException(attrs.getPositionDescription()
- + ": Error inflating class " + qualifiedName, e);
- }
- }
-
- @Override
- protected T onCreateItem(String tagName, AttributeSet attrs) {
- return createItem(tagName, mDefaultPackage, attrs);
- }
-
- /**
- * Sets the default package that will be searched for classes to construct for tag names that
- * have no explicit package.
- *
- * @param defaultPackage The default package. This will be prepended to the tag name, so it
- * should end with a period.
- */
- public void setDefaultPackage(@Nullable String defaultPackage) {
- mDefaultPackage = defaultPackage;
- }
-
- /**
- * Returns the default package, or null if it is not set.
- *
- * @see #setDefaultPackage(String)
- * @return The default package.
- */
- @Nullable
- public String getDefaultPackage() {
- return mDefaultPackage;
+ Class<? extends T> clazz =
+ (Class<? extends T>) context.getClassLoader().loadClass(qualifiedName);
+ constructor = clazz.getConstructor(CONSTRUCTOR_SIGNATURE);
+ constructor.setAccessible(true);
+ constructorMap.put(tagName, constructor);
+ }
+
+ tempConstructorArgs[0] = context;
+ tempConstructorArgs[1] = attrs;
+ final T item = constructor.newInstance(tempConstructorArgs);
+ tempConstructorArgs[0] = null;
+ tempConstructorArgs[1] = null;
+ return item;
+ } catch (Exception e) {
+ throw new InflateException(
+ attrs.getPositionDescription() + ": Error inflating class " + qualifiedName, e);
}
+ }
+
+ @Override
+ protected T onCreateItem(String tagName, AttributeSet attrs) {
+ return createItem(tagName, defaultPackage, attrs);
+ }
+
+ /**
+ * Sets the default package that will be searched for classes to construct for tag names that have
+ * no explicit package.
+ *
+ * @param defaultPackage The default package. This will be prepended to the tag name, so it should
+ * end with a period.
+ */
+ public void setDefaultPackage(@Nullable String defaultPackage) {
+ this.defaultPackage = defaultPackage;
+ }
+
+ /**
+ * Returns the default package, or null if it is not set.
+ *
+ * @see #setDefaultPackage(String)
+ * @return The default package.
+ */
+ @Nullable
+ public String getDefaultPackage() {
+ return defaultPackage;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/SimpleInflater.java b/library/main/src/com/android/setupwizardlib/items/SimpleInflater.java
index 0b12aca..767362c 100644
--- a/library/main/src/com/android/setupwizardlib/items/SimpleInflater.java
+++ b/library/main/src/com/android/setupwizardlib/items/SimpleInflater.java
@@ -18,18 +18,15 @@ package com.android.setupwizardlib.items;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import androidx.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import android.view.InflateException;
-
-import androidx.annotation.NonNull;
-
+import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.IOException;
-
/**
* A simple XML inflater, which takes care of moving the parser to the correct position. Subclasses
* need to implement {@link #onCreateItem(String, AttributeSet)} to create an object representation
@@ -40,154 +37,154 @@ import java.io.IOException;
*/
public abstract class SimpleInflater<T> {
- private static final String TAG = "SimpleInflater";
- private static final boolean DEBUG = false;
-
- protected final Resources mResources;
-
- /**
- * Create a new inflater instance associated with a particular Resources bundle.
- *
- * @param resources The Resources class used to resolve given resource IDs.
- */
- protected SimpleInflater(@NonNull Resources resources) {
- mResources = resources;
+ private static final String TAG = "SimpleInflater";
+ private static final boolean DEBUG = false;
+
+ protected final Resources mResources;
+
+ /**
+ * Create a new inflater instance associated with a particular Resources bundle.
+ *
+ * @param resources The Resources class used to resolve given resource IDs.
+ */
+ protected SimpleInflater(@NonNull Resources resources) {
+ mResources = resources;
+ }
+
+ public Resources getResources() {
+ return mResources;
+ }
+
+ /**
+ * Inflate a new hierarchy from the specified XML resource. Throws InflaterException if there is
+ * an error.
+ *
+ * @param resId ID for an XML resource to load (e.g. <code>R.xml.my_xml</code>)
+ * @return The root of the inflated hierarchy.
+ */
+ public T inflate(int resId) {
+ XmlResourceParser parser = getResources().getXml(resId);
+ try {
+ return inflate(parser);
+ } finally {
+ parser.close();
}
-
- public Resources getResources() {
- return mResources;
- }
-
- /**
- * Inflate a new hierarchy from the specified XML resource. Throws InflaterException if there is
- * an error.
- *
- * @param resId ID for an XML resource to load (e.g. <code>R.xml.my_xml</code>)
- * @return The root of the inflated hierarchy.
- */
- public T inflate(int resId) {
- XmlResourceParser parser = getResources().getXml(resId);
- try {
- return inflate(parser);
- } finally {
- parser.close();
- }
- }
-
- /**
- * Inflate a new hierarchy from the specified XML node. Throws InflaterException if there is an
- * error.
- * <p>
- * <em><strong>Important</strong></em>&nbsp;&nbsp;&nbsp;For performance
- * reasons, inflation relies heavily on pre-processing of XML files
- * that is done at build time. Therefore, it is not currently possible to
- * use inflater with an XmlPullParser over a plain XML file at runtime.
- *
- * @param parser XML dom node containing the description of the hierarchy.
- * @return The root of the inflated hierarchy.
- */
- public T inflate(XmlPullParser parser) {
- final AttributeSet attrs = Xml.asAttributeSet(parser);
- T createdItem;
-
- try {
- // Look for the root node.
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- // continue
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(parser.getPositionDescription()
- + ": No start tag found!");
- }
-
- createdItem = createItemFromTag(parser.getName(), attrs);
-
- rInflate(parser, createdItem, attrs);
- } catch (XmlPullParserException e) {
- throw new InflateException(e.getMessage(), e);
- } catch (IOException e) {
- throw new InflateException(parser.getPositionDescription() + ": " + e.getMessage(), e);
- }
-
- return createdItem;
+ }
+
+ /**
+ * Inflate a new hierarchy from the specified XML node. Throws InflaterException if there is an
+ * error.
+ *
+ * <p><em><strong>Important</strong></em>&nbsp;&nbsp;&nbsp;For performance reasons, inflation
+ * relies heavily on pre-processing of XML files that is done at build time. Therefore, it is not
+ * currently possible to use inflater with an XmlPullParser over a plain XML file at runtime.
+ *
+ * @param parser XML dom node containing the description of the hierarchy.
+ * @return The root of the inflated hierarchy.
+ */
+ public T inflate(XmlPullParser parser) {
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ T createdItem;
+
+ try {
+ // Look for the root node.
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // continue
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(parser.getPositionDescription() + ": No start tag found!");
+ }
+
+ createdItem = createItemFromTag(parser.getName(), attrs);
+
+ rInflate(parser, createdItem, attrs);
+ } catch (XmlPullParserException e) {
+ throw new InflateException(e.getMessage(), e);
+ } catch (IOException e) {
+ throw new InflateException(parser.getPositionDescription() + ": " + e.getMessage(), e);
}
- /**
- * This routine is responsible for creating the correct subclass of item
- * given the xml element name.
- *
- * @param tagName The XML tag name for the item to be created.
- * @param attrs An AttributeSet of attributes to apply to the item.
- * @return The item created.
- */
- protected abstract T onCreateItem(String tagName, AttributeSet attrs);
-
- private T createItemFromTag(String name, AttributeSet attrs) {
- try {
- T item = onCreateItem(name, attrs);
- if (DEBUG) Log.v(TAG, item + " created for <" + name + ">");
- return item;
- } catch (InflateException e) {
- throw e;
- } catch (Exception e) {
- throw new InflateException(attrs.getPositionDescription()
- + ": Error inflating class " + name, e);
- }
+ return createdItem;
+ }
+
+ /**
+ * This routine is responsible for creating the correct subclass of item given the xml element
+ * name.
+ *
+ * @param tagName The XML tag name for the item to be created.
+ * @param attrs An AttributeSet of attributes to apply to the item.
+ * @return The item created.
+ */
+ protected abstract T onCreateItem(String tagName, AttributeSet attrs);
+
+ private T createItemFromTag(String name, AttributeSet attrs) {
+ try {
+ T item = onCreateItem(name, attrs);
+ if (DEBUG) {
+ Log.v(TAG, item + " created for <" + name + ">");
+ }
+ return item;
+ } catch (InflateException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new InflateException(
+ attrs.getPositionDescription() + ": Error inflating class " + name, e);
}
+ }
- /**
- * Recursive method used to descend down the xml hierarchy and instantiate
- * items, instantiate their children, and then call onFinishInflate().
- */
- private void rInflate(XmlPullParser parser, T parent, final AttributeSet attrs)
- throws XmlPullParserException, IOException {
- final int depth = parser.getDepth();
-
- int type;
- while (((type = parser.next()) != XmlPullParser.END_TAG
- || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ /**
+ * Recursive method used to descend down the xml hierarchy and instantiate items, instantiate
+ * their children, and then call onFinishInflate().
+ */
+ private void rInflate(XmlPullParser parser, T parent, final AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ final int depth = parser.getDepth();
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
+ int type;
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
- if (onInterceptCreateItem(parser, parent, attrs)) {
- continue;
- }
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
- String name = parser.getName();
- T item = createItemFromTag(name, attrs);
+ if (onInterceptCreateItem(parser, parent, attrs)) {
+ continue;
+ }
- onAddChildItem(parent, item);
+ String name = parser.getName();
+ T item = createItemFromTag(name, attrs);
- rInflate(parser, item, attrs);
- }
- }
+ onAddChildItem(parent, item);
- /**
- * Whether item creation should be intercepted to perform custom handling on the parser rather
- * than creating an object from it. This is used in rare cases where a tag doesn't correspond
- * to creation of an object.
- *
- * The parser will be pointing to the start of a tag, you must stop parsing and return when you
- * reach the end of this element. That is, this method is responsible for parsing the element
- * at the given position together with all of its child tags.
- *
- * Note that parsing of the root tag cannot be intercepted.
- *
- * @param parser XML dom node containing the description of the hierarchy.
- * @param parent The item that should be the parent of whatever you create.
- * @param attrs An AttributeSet of attributes to apply to the item.
- * @return True to continue parsing without calling {@link #onCreateItem(String, AttributeSet)},
- * or false if this inflater should proceed to create an item.
- */
- protected boolean onInterceptCreateItem(XmlPullParser parser, T parent, AttributeSet attrs)
- throws XmlPullParserException {
- return false;
+ rInflate(parser, item, attrs);
}
-
- protected abstract void onAddChildItem(T parent, T child);
+ }
+
+ /**
+ * Whether item creation should be intercepted to perform custom handling on the parser rather
+ * than creating an object from it. This is used in rare cases where a tag doesn't correspond to
+ * creation of an object.
+ *
+ * <p>The parser will be pointing to the start of a tag, you must stop parsing and return when you
+ * reach the end of this element. That is, this method is responsible for parsing the element at
+ * the given position together with all of its child tags.
+ *
+ * <p>Note that parsing of the root tag cannot be intercepted.
+ *
+ * @param parser XML dom node containing the description of the hierarchy.
+ * @param parent The item that should be the parent of whatever you create.
+ * @param attrs An AttributeSet of attributes to apply to the item.
+ * @return True to continue parsing without calling {@link #onCreateItem(String, AttributeSet)},
+ * or false if this inflater should proceed to create an item.
+ */
+ protected boolean onInterceptCreateItem(XmlPullParser parser, T parent, AttributeSet attrs)
+ throws XmlPullParserException {
+ return false;
+ }
+
+ protected abstract void onAddChildItem(T parent, T child);
}
diff --git a/library/main/src/com/android/setupwizardlib/span/LinkSpan.java b/library/main/src/com/android/setupwizardlib/span/LinkSpan.java
index 3dd783b..49ce1b9 100644
--- a/library/main/src/com/android/setupwizardlib/span/LinkSpan.java
+++ b/library/main/src/com/android/setupwizardlib/span/LinkSpan.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Typeface;
import android.os.Build;
+import androidx.annotation.Nullable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextPaint;
@@ -28,126 +29,120 @@ import android.util.Log;
import android.view.View;
import android.widget.TextView;
-import androidx.annotation.Nullable;
-
/**
* A clickable span that will listen for click events and send it back to the context. To use this
- * class, implement {@link OnLinkClickListener} in your TextView, or use
- * {@link com.android.setupwizardlib.view.RichTextView#setOnClickListener(View.OnClickListener)}.
+ * class, implement {@link OnLinkClickListener} in your TextView, or use {@link
+ * com.android.setupwizardlib.view.RichTextView#setOnClickListener(View.OnClickListener)}.
*
- * <p />Note on accessibility: For TalkBack to be able to traverse and interact with the links, you
+ * <p>Note on accessibility: For TalkBack to be able to traverse and interact with the links, you
* should use {@code LinkAccessibilityHelper} in your {@code TextView} subclass. Optionally you can
* also use {@code RichTextView}, which includes link support.
*/
public class LinkSpan extends ClickableSpan {
- /*
- * Implementation note: When the orientation changes, TextView retains a reference to this span
- * instead of writing it to a parcel (ClickableSpan is not Parcelable). If this class has any
- * reference to the containing Activity (i.e. the activity context, or any views in the
- * activity), it will cause memory leak.
- */
+ /*
+ * Implementation note: When the orientation changes, TextView retains a reference to this span
+ * instead of writing it to a parcel (ClickableSpan is not Parcelable). If this class has any
+ * reference to the containing Activity (i.e. the activity context, or any views in the
+ * activity), it will cause memory leak.
+ */
- /* static section */
+ /* static section */
- private static final String TAG = "LinkSpan";
+ private static final String TAG = "LinkSpan";
- private static final Typeface TYPEFACE_MEDIUM =
- Typeface.create("sans-serif-medium", Typeface.NORMAL);
+ private static final Typeface TYPEFACE_MEDIUM =
+ Typeface.create("sans-serif-medium", Typeface.NORMAL);
- /**
- * @deprecated Use {@link OnLinkClickListener}
- */
- @Deprecated
- public interface OnClickListener {
- void onClick(LinkSpan span);
- }
+ /** @deprecated Use {@link OnLinkClickListener} */
+ @Deprecated
+ public interface OnClickListener {
+ void onClick(LinkSpan span);
+ }
+
+ /**
+ * Listener that is invoked when a link span is clicked. If the containing view of this span
+ * implements this interface, this will be invoked when the link is clicked.
+ */
+ public interface OnLinkClickListener {
/**
- * Listener that is invoked when a link span is clicked. If the containing view of this span
- * implements this interface, this will be invoked when the link is clicked.
+ * Called when a link has been clicked.
+ *
+ * @param span The span that was clicked.
+ * @return True if the click was handled, stopping further propagation of the click event.
*/
- public interface OnLinkClickListener {
-
- /**
- * Called when a link has been clicked.
- *
- * @param span The span that was clicked.
- * @return True if the click was handled, stopping further propagation of the click event.
- */
- boolean onLinkClick(LinkSpan span);
+ boolean onLinkClick(LinkSpan span);
+ }
+
+ /* non-static section */
+
+ private final String id;
+
+ public LinkSpan(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (dispatchClick(view)) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // Prevent the touch event from bubbling up to the parent views.
+ view.cancelPendingInputEvents();
+ }
+ } else {
+ Log.w(TAG, "Dropping click event. No listener attached.");
}
-
- /* non-static section */
-
- private final String mId;
-
- public LinkSpan(String id) {
- mId = id;
+ if (view instanceof TextView) {
+ // Remove the highlight effect when the click happens by clearing the selection
+ CharSequence text = ((TextView) view).getText();
+ if (text instanceof Spannable) {
+ Selection.setSelection((Spannable) text, 0);
+ }
}
+ }
- @Override
- public void onClick(View view) {
- if (dispatchClick(view)) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- // Prevent the touch event from bubbling up to the parent views.
- view.cancelPendingInputEvents();
- }
- } else {
- Log.w(TAG, "Dropping click event. No listener attached.");
- }
- if (view instanceof TextView) {
- // Remove the highlight effect when the click happens by clearing the selection
- CharSequence text = ((TextView) view).getText();
- if (text instanceof Spannable) {
- Selection.setSelection((Spannable) text, 0);
- }
- }
+ private boolean dispatchClick(View view) {
+ boolean handled = false;
+ if (view instanceof OnLinkClickListener) {
+ handled = ((OnLinkClickListener) view).onLinkClick(this);
}
-
- private boolean dispatchClick(View view) {
- boolean handled = false;
- if (view instanceof OnLinkClickListener) {
- handled = ((OnLinkClickListener) view).onLinkClick(this);
- }
- if (!handled) {
- final OnClickListener listener = getLegacyListenerFromContext(view.getContext());
- if (listener != null) {
- listener.onClick(this);
- handled = true;
- }
- }
- return handled;
+ if (!handled) {
+ final OnClickListener listener = getLegacyListenerFromContext(view.getContext());
+ if (listener != null) {
+ listener.onClick(this);
+ handled = true;
+ }
}
-
- /**
- * @deprecated Deprecated together with {@link OnClickListener}
- */
- @Nullable
- @Deprecated
- private OnClickListener getLegacyListenerFromContext(@Nullable Context context) {
- while (true) {
- if (context instanceof OnClickListener) {
- return (OnClickListener) context;
- } else if (context instanceof ContextWrapper) {
- // Unwrap any context wrapper, in base the base context implements onClickListener.
- // ContextWrappers cannot have circular base contexts, so at some point this will
- // reach the one of the other cases and return.
- context = ((ContextWrapper) context).getBaseContext();
- } else {
- return null;
- }
- }
- }
-
- @Override
- public void updateDrawState(TextPaint drawState) {
- super.updateDrawState(drawState);
- drawState.setUnderlineText(false);
- drawState.setTypeface(TYPEFACE_MEDIUM);
- }
-
- public String getId() {
- return mId;
+ return handled;
+ }
+
+ /** @deprecated Deprecated together with {@link OnClickListener} */
+ @Nullable
+ @Deprecated
+ private OnClickListener getLegacyListenerFromContext(@Nullable Context context) {
+ while (true) {
+ if (context instanceof OnClickListener) {
+ return (OnClickListener) context;
+ } else if (context instanceof ContextWrapper) {
+ // Unwrap any context wrapper, in base the base context implements onClickListener.
+ // ContextWrappers cannot have circular base contexts, so at some point this will
+ // reach the one of the other cases and return.
+ context = ((ContextWrapper) context).getBaseContext();
+ } else {
+ return null;
+ }
}
+ }
+
+ @Override
+ public void updateDrawState(TextPaint drawState) {
+ super.updateDrawState(drawState);
+ drawState.setUnderlineText(false);
+ drawState.setTypeface(TYPEFACE_MEDIUM);
+ }
+
+ public String getId() {
+ return id;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/span/SpanHelper.java b/library/main/src/com/android/setupwizardlib/span/SpanHelper.java
index d75e338..4037e6d 100644
--- a/library/main/src/com/android/setupwizardlib/span/SpanHelper.java
+++ b/library/main/src/com/android/setupwizardlib/span/SpanHelper.java
@@ -23,14 +23,14 @@ import android.text.Spannable;
*/
public class SpanHelper {
- /**
- * Add {@code newSpan} at the same start and end indices as {@code oldSpan} and remove
- * {@code oldSpan} from the {@code spannable}.
- */
- public static void replaceSpan(Spannable spannable, Object oldSpan, Object newSpan) {
- final int spanStart = spannable.getSpanStart(oldSpan);
- final int spanEnd = spannable.getSpanEnd(oldSpan);
- spannable.removeSpan(oldSpan);
- spannable.setSpan(newSpan, spanStart, spanEnd, 0);
- }
+ /**
+ * Add {@code newSpan} at the same start and end indices as {@code oldSpan} and remove {@code
+ * oldSpan} from the {@code spannable}.
+ */
+ public static void replaceSpan(Spannable spannable, Object oldSpan, Object newSpan) {
+ final int spanStart = spannable.getSpanStart(oldSpan);
+ final int spanEnd = spannable.getSpanEnd(oldSpan);
+ spannable.removeSpan(oldSpan);
+ spannable.setSpan(newSpan, spanStart, spanEnd, 0);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/ButtonFooterMixin.java b/library/main/src/com/android/setupwizardlib/template/ButtonFooterMixin.java
index a8580a3..c872f6b 100644
--- a/library/main/src/com/android/setupwizardlib/template/ButtonFooterMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/ButtonFooterMixin.java
@@ -18,6 +18,10 @@ package com.android.setupwizardlib.template;
import android.annotation.SuppressLint;
import android.content.Context;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.annotation.StyleRes;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@@ -25,12 +29,6 @@ import android.view.ViewStub;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-import androidx.annotation.StyleRes;
-
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.TemplateLayout;
@@ -41,134 +39,131 @@ import com.android.setupwizardlib.TemplateLayout;
*/
public class ButtonFooterMixin implements Mixin {
- private final Context mContext;
-
- @Nullable
- private final ViewStub mFooterStub;
-
- private LinearLayout mButtonContainer;
-
- /**
- * Create a mixin for managing buttons on the footer.
- *
- * @param layout The {@link TemplateLayout} containing this mixin.
- */
- public ButtonFooterMixin(TemplateLayout layout) {
- mContext = layout.getContext();
- mFooterStub = (ViewStub) layout.findManagedViewById(R.id.suw_layout_footer);
- }
-
- /**
- * Add a button with the given text and style. Common style for GLIF are
- * {@code SuwGlifButton.Primary} and {@code SuwGlifButton.Secondary}.
- *
- * @param text The label for the button.
- * @param theme Theme resource to be used for this button. Since this is applied as a theme,
- * the resource will typically apply {@code android:buttonStyle} so it will be
- * applied to the button as a style as well.
- *
- * @return The button that was created.
- */
- public Button addButton(CharSequence text, @StyleRes int theme) {
- Button button = createThemedButton(mContext, theme);
- button.setText(text);
- return addButton(button);
- }
-
- /**
- * Add a button with the given text and style. Common style for GLIF are
- * {@code SuwGlifButton.Primary} and {@code SuwGlifButton.Secondary}.
- *
- * @param text The label for the button.
- * @param theme Theme resource to be used for this button. Since this is applied as a theme,
- * the resource will typically apply {@code android:buttonStyle} so it will be
- * applied to the button as a style as well.
- *
- * @return The button that was created.
- */
- public Button addButton(@StringRes int text, @StyleRes int theme) {
- Button button = createThemedButton(mContext, theme);
- button.setText(text);
- return addButton(button);
- }
-
- /**
- * Add a button to the footer.
- *
- * @param button The button to be added to the footer.
- * @return The button that was added.
- */
- public Button addButton(Button button) {
- final LinearLayout buttonContainer = ensureFooterInflated();
- buttonContainer.addView(button);
- return button;
- }
-
- /**
- * Add a space to the footer. Spaces will share the remaining space of footer, so for example,
- * [Button] [space] [Button] [space] [Button] will give you 3 buttons, left, center, and right
- * aligned.
- *
- * @return The view that was used as space.
- */
- public View addSpace() {
- final LinearLayout buttonContainer = ensureFooterInflated();
- View space = new View(buttonContainer.getContext());
- space.setLayoutParams(new LayoutParams(0, 0, 1.0f));
- space.setVisibility(View.INVISIBLE);
- buttonContainer.addView(space);
- return space;
+ private final Context context;
+
+ @Nullable private final ViewStub footerStub;
+
+ private LinearLayout buttonContainer;
+
+ /**
+ * Create a mixin for managing buttons on the footer.
+ *
+ * @param layout The {@link TemplateLayout} containing this mixin.
+ */
+ public ButtonFooterMixin(TemplateLayout layout) {
+ context = layout.getContext();
+ footerStub = (ViewStub) layout.findManagedViewById(R.id.suw_layout_footer);
+ }
+
+ /**
+ * Add a button with the given text and style. Common style for GLIF are {@code
+ * SuwGlifButton.Primary} and {@code SuwGlifButton.Secondary}.
+ *
+ * @param text The label for the button.
+ * @param theme Theme resource to be used for this button. Since this is applied as a theme, the
+ * resource will typically apply {@code android:buttonStyle} so it will be applied to the
+ * button as a style as well.
+ * @return The button that was created.
+ */
+ public Button addButton(CharSequence text, @StyleRes int theme) {
+ Button button = createThemedButton(context, theme);
+ button.setText(text);
+ return addButton(button);
+ }
+
+ /**
+ * Add a button with the given text and style. Common style for GLIF are {@code
+ * SuwGlifButton.Primary} and {@code SuwGlifButton.Secondary}.
+ *
+ * @param text The label for the button.
+ * @param theme Theme resource to be used for this button. Since this is applied as a theme, the
+ * resource will typically apply {@code android:buttonStyle} so it will be applied to the
+ * button as a style as well.
+ * @return The button that was created.
+ */
+ public Button addButton(@StringRes int text, @StyleRes int theme) {
+ Button button = createThemedButton(context, theme);
+ button.setText(text);
+ return addButton(button);
+ }
+
+ /**
+ * Add a button to the footer.
+ *
+ * @param button The button to be added to the footer.
+ * @return The button that was added.
+ */
+ public Button addButton(Button button) {
+ final LinearLayout buttonContainer = ensureFooterInflated();
+ buttonContainer.addView(button);
+ return button;
+ }
+
+ /**
+ * Add a space to the footer. Spaces will share the remaining space of footer, so for example,
+ * [Button] [space] [Button] [space] [Button] will give you 3 buttons, left, center, and right
+ * aligned.
+ *
+ * @return The view that was used as space.
+ */
+ public View addSpace() {
+ final LinearLayout buttonContainer = ensureFooterInflated();
+ View space = new View(buttonContainer.getContext());
+ space.setLayoutParams(new LayoutParams(0, 0, 1.0f));
+ space.setVisibility(View.INVISIBLE);
+ buttonContainer.addView(space);
+ return space;
+ }
+
+ /**
+ * Remove a previously added button.
+ *
+ * @param button The button to be removed.
+ */
+ public void removeButton(Button button) {
+ if (buttonContainer != null) {
+ buttonContainer.removeView(button);
}
-
- /**
- * Remove a previously added button.
- *
- * @param button The button to be removed.
- */
- public void removeButton(Button button) {
- if (mButtonContainer != null) {
- mButtonContainer.removeView(button);
- }
- }
-
- /**
- * Remove a previously added space.
- *
- * @param space The space to be removed.
- */
- public void removeSpace(View space) {
- if (mButtonContainer != null) {
- mButtonContainer.removeView(space);
- }
+ }
+
+ /**
+ * Remove a previously added space.
+ *
+ * @param space The space to be removed.
+ */
+ public void removeSpace(View space) {
+ if (buttonContainer != null) {
+ buttonContainer.removeView(space);
}
-
- /**
- * Remove all views, including spaces, from the footer. Note that if the footer container is
- * already inflated, this will not remove the container itself.
- */
- public void removeAllViews() {
- if (mButtonContainer != null) {
- mButtonContainer.removeAllViews();
- }
+ }
+
+ /**
+ * Remove all views, including spaces, from the footer. Note that if the footer container is
+ * already inflated, this will not remove the container itself.
+ */
+ public void removeAllViews() {
+ if (buttonContainer != null) {
+ buttonContainer.removeAllViews();
}
-
- @NonNull
- private LinearLayout ensureFooterInflated() {
- if (mButtonContainer == null) {
- if (mFooterStub == null) {
- throw new IllegalStateException("Footer stub is not found in this template");
- }
- mFooterStub.setLayoutResource(R.layout.suw_glif_footer_button_bar);
- mButtonContainer = (LinearLayout) mFooterStub.inflate();
- }
- return mButtonContainer;
- }
-
- @SuppressLint("InflateParams")
- private Button createThemedButton(Context context, @StyleRes int theme) {
- // Inflate a single button from XML, which when using support lib, will take advantage of
- // the injected layout inflater and give us AppCompatButton instead.
- LayoutInflater inflater = LayoutInflater.from(new ContextThemeWrapper(context, theme));
- return (Button) inflater.inflate(R.layout.suw_button, null, false);
+ }
+
+ @NonNull
+ private LinearLayout ensureFooterInflated() {
+ if (buttonContainer == null) {
+ if (footerStub == null) {
+ throw new IllegalStateException("Footer stub is not found in this template");
+ }
+ footerStub.setLayoutResource(R.layout.suw_glif_footer_button_bar);
+ buttonContainer = (LinearLayout) footerStub.inflate();
}
+ return buttonContainer;
+ }
+
+ @SuppressLint("InflateParams")
+ private Button createThemedButton(Context context, @StyleRes int theme) {
+ // Inflate a single button from XML, which when using support lib, will take advantage of
+ // the injected layout inflater and give us AppCompatButton instead.
+ LayoutInflater inflater = LayoutInflater.from(new ContextThemeWrapper(context, theme));
+ return (Button) inflater.inflate(R.layout.suw_button, null, false);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java b/library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java
index ccc5aad..acdaa67 100644
--- a/library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/ColoredHeaderMixin.java
@@ -20,54 +20,51 @@ import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.TextView;
-
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.TemplateLayout;
/**
* A {@link Mixin} displaying a header text that can be set to different colors. This Mixin is
- * registered to the tempalte using HeaderMixin.class, and can be retrieved using:
- * {@code (ColoredHeaderMixin) templateLayout.getMixin(HeaderMixin.class}.
+ * registered to the template using HeaderMixin.class, and can be retrieved using: {@code
+ * (ColoredHeaderMixin) templateLayout.getMixin(HeaderMixin.class}.
*/
public class ColoredHeaderMixin extends HeaderMixin {
- /**
- * {@inheritDoc}
- */
- public ColoredHeaderMixin(TemplateLayout layout, AttributeSet attrs, int defStyleAttr) {
- super(layout, attrs, defStyleAttr);
-
- final TypedArray a = layout.getContext().obtainStyledAttributes(
- attrs, R.styleable.SuwColoredHeaderMixin, defStyleAttr, 0);
+ /** {@inheritDoc} */
+ public ColoredHeaderMixin(TemplateLayout layout, AttributeSet attrs, int defStyleAttr) {
+ super(layout, attrs, defStyleAttr);
- // Set the header color
- final ColorStateList headerColor =
- a.getColorStateList(R.styleable.SuwColoredHeaderMixin_suwHeaderColor);
- if (headerColor != null) {
- setColor(headerColor);
- }
+ final TypedArray a =
+ layout
+ .getContext()
+ .obtainStyledAttributes(attrs, R.styleable.SuwColoredHeaderMixin, defStyleAttr, 0);
- a.recycle();
+ // Set the header color
+ final ColorStateList headerColor =
+ a.getColorStateList(R.styleable.SuwColoredHeaderMixin_suwHeaderColor);
+ if (headerColor != null) {
+ setColor(headerColor);
}
- /**
- * Sets the color of the header text. This can also be set via XML using
- * {@code app:suwHeaderColor}.
- *
- * @param color The text color of the header.
- */
- public void setColor(ColorStateList color) {
- final TextView titleView = getTextView();
- if (titleView != null) {
- titleView.setTextColor(color);
- }
- }
+ a.recycle();
+ }
- /**
- * @return The current text color of the header.
- */
- public ColorStateList getColor() {
- final TextView titleView = getTextView();
- return titleView != null ? titleView.getTextColors() : null;
+ /**
+ * Sets the color of the header text. This can also be set via XML using {@code
+ * app:suwHeaderColor}.
+ *
+ * @param color The text color of the header.
+ */
+ public void setColor(ColorStateList color) {
+ final TextView titleView = getTextView();
+ if (titleView != null) {
+ titleView.setTextColor(color);
}
+ }
+
+ /** @return The current text color of the header. */
+ public ColorStateList getColor() {
+ final TextView titleView = getTextView();
+ return titleView != null ? titleView.getTextColors() : null;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/HeaderMixin.java b/library/main/src/com/android/setupwizardlib/template/HeaderMixin.java
index 604de9a..7d7fb4a 100644
--- a/library/main/src/com/android/setupwizardlib/template/HeaderMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/HeaderMixin.java
@@ -17,80 +17,74 @@
package com.android.setupwizardlib.template;
import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
import androidx.annotation.AttrRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
+import android.util.AttributeSet;
+import android.widget.TextView;
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.TemplateLayout;
-/**
- * A {@link Mixin} for setting and getting the header text.
- */
+/** A {@link Mixin} for setting and getting the header text. */
public class HeaderMixin implements Mixin {
- private TemplateLayout mTemplateLayout;
-
- /**
- * @param layout The layout this Mixin belongs to.
- * @param attrs XML attributes given to the layout.
- * @param defStyleAttr The default style attribute as given to the constructor of the layout.
- */
- public HeaderMixin(@NonNull TemplateLayout layout, @Nullable AttributeSet attrs,
- @AttrRes int defStyleAttr) {
- mTemplateLayout = layout;
+ private final TemplateLayout templateLayout;
- final TypedArray a = layout.getContext().obtainStyledAttributes(
- attrs, R.styleable.SuwHeaderMixin, defStyleAttr, 0);
+ /**
+ * @param layout The layout this Mixin belongs to.
+ * @param attrs XML attributes given to the layout.
+ * @param defStyleAttr The default style attribute as given to the constructor of the layout.
+ */
+ public HeaderMixin(
+ @NonNull TemplateLayout layout, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
+ templateLayout = layout;
- // Set the header text
- final CharSequence headerText = a.getText(R.styleable.SuwHeaderMixin_suwHeaderText);
- if (headerText != null) {
- setText(headerText);
- }
+ final TypedArray a =
+ layout
+ .getContext()
+ .obtainStyledAttributes(attrs, R.styleable.SuwHeaderMixin, defStyleAttr, 0);
- a.recycle();
+ // Set the header text
+ final CharSequence headerText = a.getText(R.styleable.SuwHeaderMixin_suwHeaderText);
+ if (headerText != null) {
+ setText(headerText);
}
- /**
- * @return The TextView displaying the header.
- */
- public TextView getTextView() {
- return (TextView) mTemplateLayout.findManagedViewById(R.id.suw_layout_title);
- }
+ a.recycle();
+ }
- /**
- * Sets the header text. This can also be set via the XML attribute {@code app:suwHeaderText}.
- *
- * @param title The resource ID of the text to be set as header.
- */
- public void setText(int title) {
- final TextView titleView = getTextView();
- if (titleView != null) {
- titleView.setText(title);
- }
- }
+ /** @return The TextView displaying the header. */
+ public TextView getTextView() {
+ return (TextView) templateLayout.findManagedViewById(R.id.suw_layout_title);
+ }
- /**
- * Sets the header text. This can also be set via the XML attribute {@code app:suwHeaderText}.
- *
- * @param title The text to be set as header.
- */
- public void setText(CharSequence title) {
- final TextView titleView = getTextView();
- if (titleView != null) {
- titleView.setText(title);
- }
+ /**
+ * Sets the header text. This can also be set via the XML attribute {@code app:suwHeaderText}.
+ *
+ * @param title The resource ID of the text to be set as header.
+ */
+ public void setText(int title) {
+ final TextView titleView = getTextView();
+ if (titleView != null) {
+ titleView.setText(title);
}
+ }
- /**
- * @return The current header text.
- */
- public CharSequence getText() {
- final TextView titleView = getTextView();
- return titleView != null ? titleView.getText() : null;
+ /**
+ * Sets the header text. This can also be set via the XML attribute {@code app:suwHeaderText}.
+ *
+ * @param title The text to be set as header.
+ */
+ public void setText(CharSequence title) {
+ final TextView titleView = getTextView();
+ if (titleView != null) {
+ titleView.setText(title);
}
+ }
+
+ /** @return The current header text. */
+ public CharSequence getText() {
+ final TextView titleView = getTextView();
+ return titleView != null ? titleView.getText() : null;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/IconMixin.java b/library/main/src/com/android/setupwizardlib/template/IconMixin.java
index 5f5c915..e28f67d 100644
--- a/library/main/src/com/android/setupwizardlib/template/IconMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/IconMixin.java
@@ -19,100 +19,88 @@ package com.android.setupwizardlib.template;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import androidx.annotation.DrawableRes;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
-
-import androidx.annotation.DrawableRes;
-
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.TemplateLayout;
-/**
- * A {@link Mixin} for setting an icon on the template layout.
- */
+/** A {@link Mixin} for setting an icon on the template layout. */
public class IconMixin implements Mixin {
- private TemplateLayout mTemplateLayout;
-
- /**
- * @param layout The template layout that this Mixin is a part of.
- * @param attrs XML attributes given to the layout.
- * @param defStyleAttr The default style attribute as given to the constructor of the layout.
- */
- public IconMixin(TemplateLayout layout, AttributeSet attrs, int defStyleAttr) {
- mTemplateLayout = layout;
- final Context context = layout.getContext();
-
- final TypedArray a =
- context.obtainStyledAttributes(attrs, R.styleable.SuwIconMixin, defStyleAttr, 0);
+ private final TemplateLayout templateLayout;
- final @DrawableRes int icon = a.getResourceId(R.styleable.SuwIconMixin_android_icon, 0);
- if (icon != 0) {
- setIcon(icon);
- }
+ /**
+ * @param layout The template layout that this Mixin is a part of.
+ * @param attrs XML attributes given to the layout.
+ * @param defStyleAttr The default style attribute as given to the constructor of the layout.
+ */
+ public IconMixin(TemplateLayout layout, AttributeSet attrs, int defStyleAttr) {
+ templateLayout = layout;
+ final Context context = layout.getContext();
- a.recycle();
- }
-
- /**
- * Sets the icon on this layout. The icon can also be set in XML using {@code android:icon}.
- *
- * @param icon A drawable icon.
- */
- public void setIcon(Drawable icon) {
- final ImageView iconView = getView();
- if (iconView != null) {
- iconView.setImageDrawable(icon);
- iconView.setVisibility(icon != null ? View.VISIBLE : View.GONE);
- }
- }
+ final TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.SuwIconMixin, defStyleAttr, 0);
- /**
- * Sets the icon on this layout. The icon can also be set in XML using {@code android:icon}.
- *
- * @param icon A drawable icon resource.
- */
- public void setIcon(@DrawableRes int icon) {
- final ImageView iconView = getView();
- if (iconView != null) {
- // Note: setImageResource on the ImageView is overridden in AppCompatImageView for
- // support lib users, which enables vector drawable compat to work on versions pre-L.
- iconView.setImageResource(icon);
- iconView.setVisibility(icon != 0 ? View.VISIBLE : View.GONE);
- }
+ final @DrawableRes int icon = a.getResourceId(R.styleable.SuwIconMixin_android_icon, 0);
+ if (icon != 0) {
+ setIcon(icon);
}
- /**
- * @return The icon previously set in {@link #setIcon(Drawable)} or {@code android:icon}
- */
- public Drawable getIcon() {
- final ImageView iconView = getView();
- return iconView != null ? iconView.getDrawable() : null;
+ a.recycle();
+ }
+
+ /**
+ * Sets the icon on this layout. The icon can also be set in XML using {@code android:icon}.
+ *
+ * @param icon A drawable icon.
+ */
+ public void setIcon(Drawable icon) {
+ final ImageView iconView = getView();
+ if (iconView != null) {
+ iconView.setImageDrawable(icon);
+ iconView.setVisibility(icon != null ? View.VISIBLE : View.GONE);
}
-
- /**
- * Sets the content description of the icon view
- */
- public void setContentDescription(CharSequence description) {
- final ImageView iconView = getView();
- if (iconView != null) {
- iconView.setContentDescription(description);
- }
+ }
+
+ /**
+ * Sets the icon on this layout. The icon can also be set in XML using {@code android:icon}.
+ *
+ * @param icon A drawable icon resource.
+ */
+ public void setIcon(@DrawableRes int icon) {
+ final ImageView iconView = getView();
+ if (iconView != null) {
+ // Note: setImageResource on the ImageView is overridden in AppCompatImageView for
+ // support lib users, which enables vector drawable compat to work on versions pre-L.
+ iconView.setImageResource(icon);
+ iconView.setVisibility(icon != 0 ? View.VISIBLE : View.GONE);
}
-
- /**
- * @return The content description of the icon view
- */
- public CharSequence getContentDescription() {
- final ImageView iconView = getView();
- return iconView != null ? iconView.getContentDescription() : null;
- }
-
- /**
- * @return The ImageView responsible for displaying the icon.
- */
- protected ImageView getView() {
- return (ImageView) mTemplateLayout.findManagedViewById(R.id.suw_layout_icon);
+ }
+
+ /** @return The icon previously set in {@link #setIcon(Drawable)} or {@code android:icon} */
+ public Drawable getIcon() {
+ final ImageView iconView = getView();
+ return iconView != null ? iconView.getDrawable() : null;
+ }
+
+ /** Sets the content description of the icon view */
+ public void setContentDescription(CharSequence description) {
+ final ImageView iconView = getView();
+ if (iconView != null) {
+ iconView.setContentDescription(description);
}
+ }
+
+ /** @return The content description of the icon view */
+ public CharSequence getContentDescription() {
+ final ImageView iconView = getView();
+ return iconView != null ? iconView.getContentDescription() : null;
+ }
+
+ /** @return The ImageView responsible for displaying the icon. */
+ protected ImageView getView() {
+ return (ImageView) templateLayout.findManagedViewById(R.id.suw_layout_icon);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/ListMixin.java b/library/main/src/com/android/setupwizardlib/template/ListMixin.java
index cbc29b5..066141e 100644
--- a/library/main/src/com/android/setupwizardlib/template/ListMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/ListMixin.java
@@ -21,16 +21,14 @@ import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Build.VERSION_CODES;
+import androidx.annotation.AttrRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.HeaderViewListAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
-
-import androidx.annotation.AttrRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.items.ItemAdapter;
@@ -38,188 +36,170 @@ import com.android.setupwizardlib.items.ItemGroup;
import com.android.setupwizardlib.items.ItemInflater;
import com.android.setupwizardlib.util.DrawableLayoutDirectionHelper;
-/**
- * A {@link Mixin} for interacting with ListViews.
- */
+/** A {@link Mixin} for interacting with ListViews. */
public class ListMixin implements Mixin {
- private TemplateLayout mTemplateLayout;
-
- @Nullable
- private ListView mListView;
-
- private Drawable mDivider;
- private Drawable mDefaultDivider;
-
- private int mDividerInsetStart;
- private int mDividerInsetEnd;
-
- /**
- * @param layout The layout this mixin belongs to.
- */
- public ListMixin(@NonNull TemplateLayout layout, @Nullable AttributeSet attrs,
- @AttrRes int defStyleAttr) {
- mTemplateLayout = layout;
-
- final Context context = layout.getContext();
- final TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.SuwListMixin, defStyleAttr, 0);
-
- final int entries = a.getResourceId(R.styleable.SuwListMixin_android_entries, 0);
- if (entries != 0) {
- final ItemGroup inflated =
- (ItemGroup) new ItemInflater(context).inflate(entries);
- setAdapter(new ItemAdapter(inflated));
- }
- int dividerInset =
- a.getDimensionPixelSize(R.styleable.SuwListMixin_suwDividerInset, -1);
- if (dividerInset != -1) {
- setDividerInset(dividerInset);
- } else {
- int dividerInsetStart =
- a.getDimensionPixelSize(R.styleable.SuwListMixin_suwDividerInsetStart, 0);
- int dividerInsetEnd =
- a.getDimensionPixelSize(R.styleable.SuwListMixin_suwDividerInsetEnd, 0);
- setDividerInsets(dividerInsetStart, dividerInsetEnd);
- }
- a.recycle();
- }
+ private final TemplateLayout templateLayout;
- /**
- * @return The list view contained in the layout, as marked by {@code @android:id/list}. This
- * will return {@code null} if the list doesn't exist in the layout.
- */
- public ListView getListView() {
- return getListViewInternal();
- }
+ @Nullable private ListView listView;
- // Client code can assume getListView() will not be null if they know their template contains
- // the list, but this mixin cannot. Any usages of getListView in this mixin needs null checks.
- @Nullable
- private ListView getListViewInternal() {
- if (mListView == null) {
- final View list = mTemplateLayout.findManagedViewById(android.R.id.list);
- if (list instanceof ListView) {
- mListView = (ListView) list;
- }
- }
- return mListView;
- }
+ private Drawable divider;
+ private Drawable defaultDivider;
- /**
- * List mixin needs to update the dividers if the layout direction has changed. This method
- * should be called when {@link View#onLayout(boolean, int, int, int, int)} of the template
- * is called.
- */
- public void onLayout() {
- if (mDivider == null) {
- // Update divider in case layout direction has just been resolved
- updateDivider();
- }
- }
+ private int dividerInsetStart;
+ private int dividerInsetEnd;
- /**
- * Gets the adapter of the list view in this layout. If the adapter is a HeaderViewListAdapter,
- * this method will unwrap it and return the underlying adapter.
- *
- * @return The adapter, or {@code null} if there is no list, or if the list has no adapter.
- */
- public ListAdapter getAdapter() {
- final ListView listView = getListViewInternal();
- if (listView != null) {
- final ListAdapter adapter = listView.getAdapter();
- if (adapter instanceof HeaderViewListAdapter) {
- return ((HeaderViewListAdapter) adapter).getWrappedAdapter();
- }
- return adapter;
- }
- return null;
- }
+ /** @param layout The layout this mixin belongs to. */
+ public ListMixin(
+ @NonNull TemplateLayout layout, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
+ templateLayout = layout;
- /**
- * Sets the adapter on the list view in this layout.
- */
- public void setAdapter(ListAdapter adapter) {
- final ListView listView = getListViewInternal();
- if (listView != null) {
- listView.setAdapter(adapter);
- }
- }
+ final Context context = layout.getContext();
+ final TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.SuwListMixin, defStyleAttr, 0);
- /**
- * @deprecated Use {@link #setDividerInsets(int, int)} instead.
- */
- @Deprecated
- public void setDividerInset(int inset) {
- setDividerInsets(inset, 0);
+ final int entries = a.getResourceId(R.styleable.SuwListMixin_android_entries, 0);
+ if (entries != 0) {
+ final ItemGroup inflated = (ItemGroup) new ItemInflater(context).inflate(entries);
+ setAdapter(new ItemAdapter(inflated));
}
-
- /**
- * Sets the start inset of the divider. This will use the default divider drawable set in the
- * theme and apply insets to it.
- *
- * @param start The number of pixels to inset on the "start" side of the list divider. Typically
- * this will be either {@code @dimen/suw_items_glif_icon_divider_inset} or
- * {@code @dimen/suw_items_glif_text_divider_inset}.
- * @param end The number of pixels to inset on the "end" side of the list divider.
- */
- public void setDividerInsets(int start, int end) {
- mDividerInsetStart = start;
- mDividerInsetEnd = end;
- updateDivider();
+ int dividerInset = a.getDimensionPixelSize(R.styleable.SuwListMixin_suwDividerInset, -1);
+ if (dividerInset != -1) {
+ setDividerInset(dividerInset);
+ } else {
+ int dividerInsetStart =
+ a.getDimensionPixelSize(R.styleable.SuwListMixin_suwDividerInsetStart, 0);
+ int dividerInsetEnd = a.getDimensionPixelSize(R.styleable.SuwListMixin_suwDividerInsetEnd, 0);
+ setDividerInsets(dividerInsetStart, dividerInsetEnd);
}
-
- /**
- * @return The number of pixels inset on the start side of the divider.
- * @deprecated This is the same as {@link #getDividerInsetStart()}. Use that instead.
- */
- @Deprecated
- public int getDividerInset() {
- return getDividerInsetStart();
+ a.recycle();
+ }
+
+ /**
+ * @return The list view contained in the layout, as marked by {@code @android:id/list}. This will
+ * return {@code null} if the list doesn't exist in the layout.
+ */
+ public ListView getListView() {
+ return getListViewInternal();
+ }
+
+ // Client code can assume getListView() will not be null if they know their template contains
+ // the list, but this mixin cannot. Any usages of getListView in this mixin needs null checks.
+ @Nullable
+ private ListView getListViewInternal() {
+ if (listView == null) {
+ final View list = templateLayout.findManagedViewById(android.R.id.list);
+ if (list instanceof ListView) {
+ listView = (ListView) list;
+ }
}
-
- /**
- * @return The number of pixels inset on the start side of the divider.
- */
- public int getDividerInsetStart() {
- return mDividerInsetStart;
+ return listView;
+ }
+
+ /**
+ * List mixin needs to update the dividers if the layout direction has changed. This method should
+ * be called when {@link View#onLayout(boolean, int, int, int, int)} of the template is called.
+ */
+ public void onLayout() {
+ if (divider == null) {
+ // Update divider in case layout direction has just been resolved
+ updateDivider();
}
-
- /**
- * @return The number of pixels inset on the end side of the divider.
- */
- public int getDividerInsetEnd() {
- return mDividerInsetEnd;
+ }
+
+ /**
+ * Gets the adapter of the list view in this layout. If the adapter is a HeaderViewListAdapter,
+ * this method will unwrap it and return the underlying adapter.
+ *
+ * @return The adapter, or {@code null} if there is no list, or if the list has no adapter.
+ */
+ public ListAdapter getAdapter() {
+ final ListView listView = getListViewInternal();
+ if (listView != null) {
+ final ListAdapter adapter = listView.getAdapter();
+ if (adapter instanceof HeaderViewListAdapter) {
+ return ((HeaderViewListAdapter) adapter).getWrappedAdapter();
+ }
+ return adapter;
}
-
- private void updateDivider() {
- final ListView listView = getListViewInternal();
- if (listView == null) {
- return;
- }
- boolean shouldUpdate = true;
- if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- shouldUpdate = mTemplateLayout.isLayoutDirectionResolved();
- }
- if (shouldUpdate) {
- if (mDefaultDivider == null) {
- mDefaultDivider = listView.getDivider();
- }
- mDivider = DrawableLayoutDirectionHelper.createRelativeInsetDrawable(
- mDefaultDivider,
- mDividerInsetStart /* start */,
- 0 /* top */,
- mDividerInsetEnd /* end */,
- 0 /* bottom */,
- mTemplateLayout);
- listView.setDivider(mDivider);
- }
+ return null;
+ }
+
+ /** Sets the adapter on the list view in this layout. */
+ public void setAdapter(ListAdapter adapter) {
+ final ListView listView = getListViewInternal();
+ if (listView != null) {
+ listView.setAdapter(adapter);
}
-
- /**
- * @return The drawable used as the divider.
- */
- public Drawable getDivider() {
- return mDivider;
+ }
+
+ /** @deprecated Use {@link #setDividerInsets(int, int)} instead. */
+ @Deprecated
+ public void setDividerInset(int inset) {
+ setDividerInsets(inset, 0);
+ }
+
+ /**
+ * Sets the start inset of the divider. This will use the default divider drawable set in the
+ * theme and apply insets to it.
+ *
+ * @param start The number of pixels to inset on the "start" side of the list divider. Typically
+ * this will be either {@code @dimen/suw_items_glif_icon_divider_inset} or
+ * {@code @dimen/suw_items_glif_text_divider_inset}.
+ * @param end The number of pixels to inset on the "end" side of the list divider.
+ */
+ public void setDividerInsets(int start, int end) {
+ dividerInsetStart = start;
+ dividerInsetEnd = end;
+ updateDivider();
+ }
+
+ /**
+ * @return The number of pixels inset on the start side of the divider.
+ * @deprecated This is the same as {@link #getDividerInsetStart()}. Use that instead.
+ */
+ @Deprecated
+ public int getDividerInset() {
+ return getDividerInsetStart();
+ }
+
+ /** @return The number of pixels inset on the start side of the divider. */
+ public int getDividerInsetStart() {
+ return dividerInsetStart;
+ }
+
+ /** @return The number of pixels inset on the end side of the divider. */
+ public int getDividerInsetEnd() {
+ return dividerInsetEnd;
+ }
+
+ private void updateDivider() {
+ final ListView listView = getListViewInternal();
+ if (listView == null) {
+ return;
}
+ boolean shouldUpdate = true;
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ shouldUpdate = templateLayout.isLayoutDirectionResolved();
+ }
+ if (shouldUpdate) {
+ if (defaultDivider == null) {
+ defaultDivider = listView.getDivider();
+ }
+ divider =
+ DrawableLayoutDirectionHelper.createRelativeInsetDrawable(
+ defaultDivider,
+ dividerInsetStart /* start */,
+ 0 /* top */,
+ dividerInsetEnd /* end */,
+ 0 /* bottom */,
+ templateLayout);
+ listView.setDivider(divider);
+ }
+ }
+
+ /** @return The drawable used as the divider. */
+ public Drawable getDivider() {
+ return divider;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegate.java b/library/main/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegate.java
index faea305..8614ff4 100644
--- a/library/main/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegate.java
+++ b/library/main/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegate.java
@@ -16,73 +16,67 @@
package com.android.setupwizardlib.template;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.util.Log;
import android.widget.AbsListView;
import android.widget.ListAdapter;
import android.widget.ListView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
import com.android.setupwizardlib.template.RequireScrollMixin.ScrollHandlingDelegate;
/**
- * {@link ScrollHandlingDelegate} which analyzes scroll events from {@link ListView} and
- * notifies {@link RequireScrollMixin} about scrollability changes.
+ * {@link ScrollHandlingDelegate} which analyzes scroll events from {@link ListView} and notifies
+ * {@link RequireScrollMixin} about scrollability changes.
*/
-public class ListViewScrollHandlingDelegate implements ScrollHandlingDelegate,
- AbsListView.OnScrollListener {
+public class ListViewScrollHandlingDelegate
+ implements ScrollHandlingDelegate, AbsListView.OnScrollListener {
- private static final String TAG = "ListViewDelegate";
+ private static final String TAG = "ListViewDelegate";
- private static final int SCROLL_DURATION = 500;
+ private static final int SCROLL_DURATION = 500;
- @NonNull
- private final RequireScrollMixin mRequireScrollMixin;
+ @NonNull private final RequireScrollMixin requireScrollMixin;
- @Nullable
- private final ListView mListView;
+ @Nullable private final ListView listView;
- public ListViewScrollHandlingDelegate(
- @NonNull RequireScrollMixin requireScrollMixin,
- @Nullable ListView listView) {
- mRequireScrollMixin = requireScrollMixin;
- mListView = listView;
- }
+ public ListViewScrollHandlingDelegate(
+ @NonNull RequireScrollMixin requireScrollMixin, @Nullable ListView listView) {
+ this.requireScrollMixin = requireScrollMixin;
+ this.listView = listView;
+ }
- @Override
- public void startListening() {
- if (mListView != null) {
- mListView.setOnScrollListener(this);
+ @Override
+ public void startListening() {
+ if (listView != null) {
+ listView.setOnScrollListener(this);
- final ListAdapter adapter = mListView.getAdapter();
- if (mListView.getLastVisiblePosition() < adapter.getCount()) {
- mRequireScrollMixin.notifyScrollabilityChange(true);
- }
- } else {
- Log.w(TAG, "Cannot require scroll. List view is null");
- }
+ final ListAdapter adapter = listView.getAdapter();
+ if (listView.getLastVisiblePosition() < adapter.getCount()) {
+ requireScrollMixin.notifyScrollabilityChange(true);
+ }
+ } else {
+ Log.w(TAG, "Cannot require scroll. List view is null");
}
+ }
- @Override
- public void pageScrollDown() {
- if (mListView != null) {
- final int height = mListView.getHeight();
- mListView.smoothScrollBy(height, SCROLL_DURATION);
- }
+ @Override
+ public void pageScrollDown() {
+ if (listView != null) {
+ final int height = listView.getHeight();
+ listView.smoothScrollBy(height, SCROLL_DURATION);
}
+ }
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- }
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {}
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
- if (firstVisibleItem + visibleItemCount >= totalItemCount) {
- mRequireScrollMixin.notifyScrollabilityChange(false);
- } else {
- mRequireScrollMixin.notifyScrollabilityChange(true);
- }
+ @Override
+ public void onScroll(
+ AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+ if (firstVisibleItem + visibleItemCount >= totalItemCount) {
+ requireScrollMixin.notifyScrollabilityChange(false);
+ } else {
+ requireScrollMixin.notifyScrollabilityChange(true);
}
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/Mixin.java b/library/main/src/com/android/setupwizardlib/template/Mixin.java
index b7b8893..b460777 100644
--- a/library/main/src/com/android/setupwizardlib/template/Mixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/Mixin.java
@@ -22,5 +22,4 @@ package com.android.setupwizardlib.template;
* @see com.android.setupwizardlib.TemplateLayout#registerMixin(Class, Mixin)
* @see com.android.setupwizardlib.TemplateLayout#getMixin(Class)
*/
-public interface Mixin {
-}
+public interface Mixin {}
diff --git a/library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java b/library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java
index df35017..2412eda 100644
--- a/library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/NavigationBarMixin.java
@@ -17,67 +17,60 @@
package com.android.setupwizardlib.template;
import android.view.View;
-
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.view.NavigationBar;
import com.android.setupwizardlib.view.NavigationBar.NavigationBarListener;
-/**
- * A {@link Mixin} for interacting with a {@link NavigationBar}.
- */
+/** A {@link Mixin} for interacting with a {@link NavigationBar}. */
public class NavigationBarMixin implements Mixin {
- private TemplateLayout mTemplateLayout;
+ private final TemplateLayout templateLayout;
- /**
- * @param layout The layout this mixin belongs to.
- */
- public NavigationBarMixin(TemplateLayout layout) {
- mTemplateLayout = layout;
- }
+ /** @param layout The layout this mixin belongs to. */
+ public NavigationBarMixin(TemplateLayout layout) {
+ templateLayout = layout;
+ }
- /**
- * @return The navigation bar instance in the layout, or null if the layout does not have a
- * navigation bar.
- */
- public NavigationBar getNavigationBar() {
- final View view = mTemplateLayout.findManagedViewById(R.id.suw_layout_navigation_bar);
- return view instanceof NavigationBar ? (NavigationBar) view : null;
- }
+ /**
+ * @return The navigation bar instance in the layout, or null if the layout does not have a
+ * navigation bar.
+ */
+ public NavigationBar getNavigationBar() {
+ final View view = templateLayout.findManagedViewById(R.id.suw_layout_navigation_bar);
+ return view instanceof NavigationBar ? (NavigationBar) view : null;
+ }
- /**
- * Sets the label of the next button.
- *
- * @param text Label of the next button.
- */
- public void setNextButtonText(int text) {
- getNavigationBar().getNextButton().setText(text);
- }
+ /**
+ * Sets the label of the next button.
+ *
+ * @param text Label of the next button.
+ */
+ public void setNextButtonText(int text) {
+ getNavigationBar().getNextButton().setText(text);
+ }
- /**
- * Sets the label of the next button.
- *
- * @param text Label of the next button.
- */
- public void setNextButtonText(CharSequence text) {
- getNavigationBar().getNextButton().setText(text);
- }
+ /**
+ * Sets the label of the next button.
+ *
+ * @param text Label of the next button.
+ */
+ public void setNextButtonText(CharSequence text) {
+ getNavigationBar().getNextButton().setText(text);
+ }
- /**
- * @return The current label of the next button.
- */
- public CharSequence getNextButtonText() {
- return getNavigationBar().getNextButton().getText();
- }
+ /** @return The current label of the next button. */
+ public CharSequence getNextButtonText() {
+ return getNavigationBar().getNextButton().getText();
+ }
- /**
- * Sets the listener to handle back and next button clicks in the navigation bar.
- *
- * @see NavigationBar#setNavigationBarListener(NavigationBarListener)
- * @see NavigationBarListener
- */
- public void setNavigationBarListener(NavigationBarListener listener) {
- getNavigationBar().setNavigationBarListener(listener);
- }
+ /**
+ * Sets the listener to handle back and next button clicks in the navigation bar.
+ *
+ * @see NavigationBar#setNavigationBarListener(NavigationBarListener)
+ * @see NavigationBarListener
+ */
+ public void setNavigationBarListener(NavigationBarListener listener) {
+ getNavigationBar().setNavigationBarListener(listener);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java b/library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java
index 504b2f0..0e128c4 100644
--- a/library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/ProgressBarMixin.java
@@ -19,121 +19,109 @@ package com.android.setupwizardlib.template;
import android.content.res.ColorStateList;
import android.os.Build;
import android.os.Build.VERSION_CODES;
+import androidx.annotation.Nullable;
import android.view.View;
import android.view.ViewStub;
import android.widget.ProgressBar;
-
-import androidx.annotation.Nullable;
-
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.TemplateLayout;
-/**
- * A {@link Mixin} for showing a progress bar.
- */
+/** A {@link Mixin} for showing a progress bar. */
public class ProgressBarMixin implements Mixin {
- private TemplateLayout mTemplateLayout;
+ private final TemplateLayout templateLayout;
- @Nullable
- private ColorStateList mColor;
+ @Nullable private ColorStateList color;
- /**
- * @param layout The layout this mixin belongs to.
- */
- public ProgressBarMixin(TemplateLayout layout) {
- mTemplateLayout = layout;
- }
+ /** @param layout The layout this mixin belongs to. */
+ public ProgressBarMixin(TemplateLayout layout) {
+ templateLayout = layout;
+ }
- /**
- * @return True if the progress bar is currently shown.
- */
- public boolean isShown() {
- final View progressBar = mTemplateLayout.findManagedViewById(R.id.suw_layout_progress);
- return progressBar != null && progressBar.getVisibility() == View.VISIBLE;
- }
+ /** @return True if the progress bar is currently shown. */
+ public boolean isShown() {
+ final View progressBar = templateLayout.findManagedViewById(R.id.suw_layout_progress);
+ return progressBar != null && progressBar.getVisibility() == View.VISIBLE;
+ }
- /**
- * Sets whether the progress bar is shown. If the progress bar has not been inflated from the
- * stub, this method will inflate the progress bar.
- *
- * @param shown True to show the progress bar, false to hide it.
- */
- public void setShown(boolean shown) {
- if (shown) {
- View progressBar = getProgressBar();
- if (progressBar != null) {
- progressBar.setVisibility(View.VISIBLE);
- }
- } else {
- View progressBar = peekProgressBar();
- if (progressBar != null) {
- progressBar.setVisibility(View.GONE);
- }
- }
+ /**
+ * Sets whether the progress bar is shown. If the progress bar has not been inflated from the
+ * stub, this method will inflate the progress bar.
+ *
+ * @param shown True to show the progress bar, false to hide it.
+ */
+ public void setShown(boolean shown) {
+ if (shown) {
+ View progressBar = getProgressBar();
+ if (progressBar != null) {
+ progressBar.setVisibility(View.VISIBLE);
+ }
+ } else {
+ View progressBar = peekProgressBar();
+ if (progressBar != null) {
+ progressBar.setVisibility(View.GONE);
+ }
}
+ }
- /**
- * Gets the progress bar in the layout. If the progress bar has not been used before, it will be
- * installed (i.e. inflated from its view stub).
- *
- * @return The progress bar of this layout. May be null only if the template used doesn't have a
- * progress bar built-in.
- */
- private ProgressBar getProgressBar() {
- final View progressBar = peekProgressBar();
- if (progressBar == null) {
- final ViewStub progressBarStub =
- (ViewStub) mTemplateLayout.findManagedViewById(R.id.suw_layout_progress_stub);
- if (progressBarStub != null) {
- progressBarStub.inflate();
- }
- setColor(mColor);
- }
- return peekProgressBar();
+ /**
+ * Gets the progress bar in the layout. If the progress bar has not been used before, it will be
+ * installed (i.e. inflated from its view stub).
+ *
+ * @return The progress bar of this layout. May be null only if the template used doesn't have a
+ * progress bar built-in.
+ */
+ private ProgressBar getProgressBar() {
+ final View progressBar = peekProgressBar();
+ if (progressBar == null) {
+ final ViewStub progressBarStub =
+ (ViewStub) templateLayout.findManagedViewById(R.id.suw_layout_progress_stub);
+ if (progressBarStub != null) {
+ progressBarStub.inflate();
+ }
+ setColor(color);
}
+ return peekProgressBar();
+ }
- /**
- * Gets the progress bar in the layout only if it has been installed.
- * {@link #setShown(boolean)} should be called before this to ensure the progress bar
- * is set up correctly.
- *
- * @return The progress bar of this layout, or null if the progress bar is not installed. The
- * null case can happen either if {@link #setShown(boolean)} with true was
- * not called before this, or if the template does not contain a progress bar.
- */
- public ProgressBar peekProgressBar() {
- return (ProgressBar) mTemplateLayout.findManagedViewById(R.id.suw_layout_progress);
- }
+ /**
+ * Gets the progress bar in the layout only if it has been installed. {@link #setShown(boolean)}
+ * should be called before this to ensure the progress bar is set up correctly.
+ *
+ * @return The progress bar of this layout, or null if the progress bar is not installed. The null
+ * case can happen either if {@link #setShown(boolean)} with true was not called before this,
+ * or if the template does not contain a progress bar.
+ */
+ public ProgressBar peekProgressBar() {
+ return (ProgressBar) templateLayout.findManagedViewById(R.id.suw_layout_progress);
+ }
- /**
- * Sets the color of the indeterminate progress bar. This method is a no-op on SDK < 21.
- */
- public void setColor(@Nullable ColorStateList color) {
- mColor = color;
- if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- final ProgressBar bar = peekProgressBar();
- if (bar != null) {
- bar.setIndeterminateTintList(color);
- if (Build.VERSION.SDK_INT >= VERSION_CODES.M || color != null) {
- // There is a bug in Lollipop where setting the progress tint color to null
- // will crash with "java.lang.NullPointerException: Attempt to invoke virtual
- // method 'int android.graphics.Paint.getAlpha()' on a null object reference"
- // at android.graphics.drawable.NinePatchDrawable.draw(:250)
- // The bug doesn't affect ProgressBar on M because it uses ShapeDrawable instead
- // of NinePatchDrawable. (commit 6a8253fdc9f4574c28b4beeeed90580ffc93734a)
- bar.setProgressBackgroundTintList(color);
- }
- }
+ /** Sets the color of the indeterminate progress bar. This method is a no-op on SDK < 21. */
+ public void setColor(@Nullable ColorStateList color) {
+ this.color = color;
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ final ProgressBar bar = peekProgressBar();
+ if (bar != null) {
+ bar.setIndeterminateTintList(color);
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.M || color != null) {
+ // There is a bug in Lollipop where setting the progress tint color to null
+ // will crash with "java.lang.NullPointerException: Attempt to invoke virtual
+ // method 'int android.graphics.Paint.getAlpha()' on a null object reference"
+ // at android.graphics.drawable.NinePatchDrawable.draw(:250)
+ // The bug doesn't affect ProgressBar on M because it uses ShapeDrawable instead
+ // of NinePatchDrawable. (commit 6a8253fdc9f4574c28b4beeeed90580ffc93734a)
+ bar.setProgressBackgroundTintList(color);
}
+ }
}
+ }
- /**
- * @return The color previously set in {@link #setColor(ColorStateList)}, or null if the color
- * is not set. In case of null, the color of the progress bar will be inherited from the theme.
- */
- @Nullable
- public ColorStateList getColor() {
- return mColor;
- }
+ /**
+ * @return The color previously set in {@link #setColor(ColorStateList)}, or null if the color is
+ * not set. In case of null, the color of the progress bar will be inherited from the theme.
+ */
+ @Nullable
+ public ColorStateList getColor() {
+ return color;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java b/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java
index fd3303b..02bcc1c 100644
--- a/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java
+++ b/library/main/src/com/android/setupwizardlib/template/RequireScrollMixin.java
@@ -18,244 +18,222 @@ package com.android.setupwizardlib.template;
import android.os.Handler;
import android.os.Looper;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
-
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.view.NavigationBar;
/**
- * A mixin to require the a scrollable container (BottomScrollView, RecyclerView or ListView) to
- * be scrolled to bottom, making sure that the user sees all content above and below the fold.
+ * A mixin to require the a scrollable container (BottomScrollView, RecyclerView or ListView) to be
+ * scrolled to bottom, making sure that the user sees all content above and below the fold.
*/
public class RequireScrollMixin implements Mixin {
- /* static section */
-
- /**
- * Listener for when the require-scroll state changes. Note that this only requires the user to
- * scroll to the bottom once - if the user scrolled to the bottom and back-up, scrolling to
- * bottom is not required again.
- */
- public interface OnRequireScrollStateChangedListener {
+ /* static section */
- /**
- * Called when require-scroll state changed.
- *
- * @param scrollNeeded True if the user should be required to scroll to bottom.
- */
- void onRequireScrollStateChanged(boolean scrollNeeded);
- }
+ /**
+ * Listener for when the require-scroll state changes. Note that this only requires the user to
+ * scroll to the bottom once - if the user scrolled to the bottom and back-up, scrolling to bottom
+ * is not required again.
+ */
+ public interface OnRequireScrollStateChangedListener {
/**
- * A delegate to detect scrollability changes and to scroll the page. This provides a layer
- * of abstraction for BottomScrollView, RecyclerView and ListView. The delegate should call
- * {@link #notifyScrollabilityChange(boolean)} when the view scrollability is changed.
- */
- interface ScrollHandlingDelegate {
-
- /**
- * Starts listening to scrollability changes at the target scrollable container.
- */
- void startListening();
-
- /**
- * Scroll the page content down by one page.
- */
- void pageScrollDown();
- }
-
- /* non-static section */
-
- @NonNull
- private final TemplateLayout mTemplateLayout;
-
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- private boolean mRequiringScrollToBottom = false;
-
- // Whether the user have seen the more button yet.
- private boolean mEverScrolledToBottom = false;
-
- private ScrollHandlingDelegate mDelegate;
-
- @Nullable
- private OnRequireScrollStateChangedListener mListener;
-
- /**
- * @param templateLayout The template containing this mixin
- */
- public RequireScrollMixin(@NonNull TemplateLayout templateLayout) {
- mTemplateLayout = templateLayout;
- }
-
- /**
- * Sets the delegate to handle scrolling. The type of delegate should depend on whether the
- * scrolling view is a BottomScrollView, RecyclerView or ListView.
- */
- public void setScrollHandlingDelegate(@NonNull ScrollHandlingDelegate delegate) {
- mDelegate = delegate;
- }
-
- /**
- * Listen to require scroll state changes. When scroll is required,
- * {@link OnRequireScrollStateChangedListener#onRequireScrollStateChanged(boolean)} is called
- * with {@code true}, and vice versa.
- */
- public void setOnRequireScrollStateChangedListener(
- @Nullable OnRequireScrollStateChangedListener listener) {
- mListener = listener;
- }
-
- /**
- * @return The scroll state listener previously set, or {@code null} if none is registered.
- */
- public OnRequireScrollStateChangedListener getOnRequireScrollStateChangedListener() {
- return mListener;
- }
-
- /**
- * Creates an {@link OnClickListener} which if scrolling is required, will scroll the page down,
- * and if scrolling is not required, delegates to the wrapped {@code listener}. Note that you
- * should call {@link #requireScroll()} as well in order to start requiring scrolling.
+ * Called when require-scroll state changed.
*
- * @param listener The listener to be invoked when scrolling is not needed and the user taps on
- * the button. If {@code null}, the click listener will be a no-op when scroll
- * is not required.
- * @return A new {@link OnClickListener} which will scroll the page down or delegate to the
- * given listener depending on the current require-scroll state.
- */
- public OnClickListener createOnClickListener(@Nullable final OnClickListener listener) {
- return new OnClickListener() {
- @Override
- public void onClick(View view) {
- if (mRequiringScrollToBottom) {
- mDelegate.pageScrollDown();
- } else if (listener != null) {
- listener.onClick(view);
- }
- }
- };
- }
-
- /**
- * Coordinate with the given navigation bar to require scrolling on the page. The more button
- * will be shown instead of the next button while scrolling is required.
+ * @param scrollNeeded True if the user should be required to scroll to bottom.
*/
- public void requireScrollWithNavigationBar(@NonNull final NavigationBar navigationBar) {
- setOnRequireScrollStateChangedListener(
- new OnRequireScrollStateChangedListener() {
- @Override
- public void onRequireScrollStateChanged(boolean scrollNeeded) {
- navigationBar.getMoreButton()
- .setVisibility(scrollNeeded ? View.VISIBLE : View.GONE);
- navigationBar.getNextButton()
- .setVisibility(scrollNeeded ? View.GONE : View.VISIBLE);
- }
- });
- navigationBar.getMoreButton().setOnClickListener(createOnClickListener(null));
- requireScroll();
- }
-
- /**
- * @see #requireScrollWithButton(Button, CharSequence, OnClickListener)
- */
- public void requireScrollWithButton(
- @NonNull Button button,
- @StringRes int moreText,
- @Nullable OnClickListener onClickListener) {
- requireScrollWithButton(button, button.getContext().getText(moreText), onClickListener);
- }
-
- /**
- * Use the given {@code button} to require scrolling. When scrolling is required, the button
- * label will change to {@code moreText}, and tapping the button will cause the page to scroll
- * down.
- *
- * <p>Note: Calling {@link View#setOnClickListener} on the button after this method will remove
- * its link to the require-scroll mechanism. If you need to do that, obtain the click listener
- * from {@link #createOnClickListener(OnClickListener)}.
- *
- * <p>Note: The normal button label is taken from the button's text at the time of calling this
- * method. Calling {@link android.widget.TextView#setText} after calling this method causes
- * undefined behavior.
- *
- * @param button The button to use for require scroll. The button's "normal" label is taken from
- * the text at the time of calling this method, and the click listener of it will
- * be replaced.
- * @param moreText The button label when scroll is required.
- * @param onClickListener The listener for clicks when scrolling is not required.
- */
- public void requireScrollWithButton(
- @NonNull final Button button,
- final CharSequence moreText,
- @Nullable OnClickListener onClickListener) {
- final CharSequence nextText = button.getText();
- button.setOnClickListener(createOnClickListener(onClickListener));
- setOnRequireScrollStateChangedListener(new OnRequireScrollStateChangedListener() {
- @Override
- public void onRequireScrollStateChanged(boolean scrollNeeded) {
- button.setText(scrollNeeded ? moreText : nextText);
- }
+ void onRequireScrollStateChanged(boolean scrollNeeded);
+ }
+
+ /**
+ * A delegate to detect scrollability changes and to scroll the page. This provides a layer of
+ * abstraction for BottomScrollView, RecyclerView and ListView. The delegate should call {@link
+ * #notifyScrollabilityChange(boolean)} when the view scrollability is changed.
+ */
+ interface ScrollHandlingDelegate {
+
+ /** Starts listening to scrollability changes at the target scrollable container. */
+ void startListening();
+
+ /** Scroll the page content down by one page. */
+ void pageScrollDown();
+ }
+
+ /* non-static section */
+
+ private final Handler handler = new Handler(Looper.getMainLooper());
+
+ private boolean requiringScrollToBottom = false;
+
+ // Whether the user have seen the more button yet.
+ private boolean everScrolledToBottom = false;
+
+ private ScrollHandlingDelegate delegate;
+
+ @Nullable private OnRequireScrollStateChangedListener listener;
+
+ /** @param templateLayout The template containing this mixin */
+ public RequireScrollMixin(@NonNull TemplateLayout templateLayout) {
+ }
+
+ /**
+ * Sets the delegate to handle scrolling. The type of delegate should depend on whether the
+ * scrolling view is a BottomScrollView, RecyclerView or ListView.
+ */
+ public void setScrollHandlingDelegate(@NonNull ScrollHandlingDelegate delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Listen to require scroll state changes. When scroll is required, {@link
+ * OnRequireScrollStateChangedListener#onRequireScrollStateChanged(boolean)} is called with {@code
+ * true}, and vice versa.
+ */
+ public void setOnRequireScrollStateChangedListener(
+ @Nullable OnRequireScrollStateChangedListener listener) {
+ this.listener = listener;
+ }
+
+ /** @return The scroll state listener previously set, or {@code null} if none is registered. */
+ public OnRequireScrollStateChangedListener getOnRequireScrollStateChangedListener() {
+ return listener;
+ }
+
+ /**
+ * Creates an {@link OnClickListener} which if scrolling is required, will scroll the page down,
+ * and if scrolling is not required, delegates to the wrapped {@code listener}. Note that you
+ * should call {@link #requireScroll()} as well in order to start requiring scrolling.
+ *
+ * @param listener The listener to be invoked when scrolling is not needed and the user taps on
+ * the button. If {@code null}, the click listener will be a no-op when scroll is not
+ * required.
+ * @return A new {@link OnClickListener} which will scroll the page down or delegate to the given
+ * listener depending on the current require-scroll state.
+ */
+ public OnClickListener createOnClickListener(@Nullable final OnClickListener listener) {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (requiringScrollToBottom) {
+ delegate.pageScrollDown();
+ } else if (listener != null) {
+ listener.onClick(view);
+ }
+ }
+ };
+ }
+
+ /**
+ * Coordinate with the given navigation bar to require scrolling on the page. The more button will
+ * be shown instead of the next button while scrolling is required.
+ */
+ public void requireScrollWithNavigationBar(@NonNull final NavigationBar navigationBar) {
+ setOnRequireScrollStateChangedListener(
+ new OnRequireScrollStateChangedListener() {
+ @Override
+ public void onRequireScrollStateChanged(boolean scrollNeeded) {
+ navigationBar.getMoreButton().setVisibility(scrollNeeded ? View.VISIBLE : View.GONE);
+ navigationBar.getNextButton().setVisibility(scrollNeeded ? View.GONE : View.VISIBLE);
+ }
});
- requireScroll();
- }
-
- /**
- * @return True if scrolling is required. Note that this mixin only requires the user to
- * scroll to the bottom once - if the user scrolled to the bottom and back-up, scrolling to
- * bottom is not required again.
- */
- public boolean isScrollingRequired() {
- return mRequiringScrollToBottom;
+ navigationBar.getMoreButton().setOnClickListener(createOnClickListener(null));
+ requireScroll();
+ }
+
+ /** @see #requireScrollWithButton(Button, CharSequence, OnClickListener) */
+ public void requireScrollWithButton(
+ @NonNull Button button, @StringRes int moreText, @Nullable OnClickListener onClickListener) {
+ requireScrollWithButton(button, button.getContext().getText(moreText), onClickListener);
+ }
+
+ /**
+ * Use the given {@code button} to require scrolling. When scrolling is required, the button label
+ * will change to {@code moreText}, and tapping the button will cause the page to scroll down.
+ *
+ * <p>Note: Calling {@link View#setOnClickListener} on the button after this method will remove
+ * its link to the require-scroll mechanism. If you need to do that, obtain the click listener
+ * from {@link #createOnClickListener(OnClickListener)}.
+ *
+ * <p>Note: The normal button label is taken from the button's text at the time of calling this
+ * method. Calling {@link android.widget.TextView#setText} after calling this method causes
+ * undefined behavior.
+ *
+ * @param button The button to use for require scroll. The button's "normal" label is taken from
+ * the text at the time of calling this method, and the click listener of it will be replaced.
+ * @param moreText The button label when scroll is required.
+ * @param onClickListener The listener for clicks when scrolling is not required.
+ */
+ public void requireScrollWithButton(
+ @NonNull final Button button,
+ final CharSequence moreText,
+ @Nullable OnClickListener onClickListener) {
+ final CharSequence nextText = button.getText();
+ button.setOnClickListener(createOnClickListener(onClickListener));
+ setOnRequireScrollStateChangedListener(
+ new OnRequireScrollStateChangedListener() {
+ @Override
+ public void onRequireScrollStateChanged(boolean scrollNeeded) {
+ button.setText(scrollNeeded ? moreText : nextText);
+ }
+ });
+ requireScroll();
+ }
+
+ /**
+ * @return True if scrolling is required. Note that this mixin only requires the user to scroll to
+ * the bottom once - if the user scrolled to the bottom and back-up, scrolling to bottom is
+ * not required again.
+ */
+ public boolean isScrollingRequired() {
+ return requiringScrollToBottom;
+ }
+
+ /**
+ * Start requiring scrolling on the layout. After calling this method, this mixin will start
+ * listening to scroll events from the scrolling container, and call {@link
+ * OnRequireScrollStateChangedListener} when the scroll state changes.
+ */
+ public void requireScroll() {
+ delegate.startListening();
+ }
+
+ /**
+ * {@link ScrollHandlingDelegate} should call this method when the scrollability of the scrolling
+ * container changed, so this mixin can recompute whether scrolling should be required.
+ *
+ * @param canScrollDown True if the view can scroll down further.
+ */
+ void notifyScrollabilityChange(boolean canScrollDown) {
+ if (canScrollDown == requiringScrollToBottom) {
+ // Already at the desired require-scroll state
+ return;
}
-
- /**
- * Start requiring scrolling on the layout. After calling this method, this mixin will start
- * listening to scroll events from the scrolling container, and call
- * {@link OnRequireScrollStateChangedListener} when the scroll state changes.
- */
- public void requireScroll() {
- mDelegate.startListening();
+ if (canScrollDown) {
+ if (!everScrolledToBottom) {
+ postScrollStateChange(true);
+ requiringScrollToBottom = true;
+ }
+ } else {
+ postScrollStateChange(false);
+ requiringScrollToBottom = false;
+ everScrolledToBottom = true;
}
-
- /**
- * {@link ScrollHandlingDelegate} should call this method when the scrollability of the
- * scrolling container changed, so this mixin can recompute whether scrolling should be
- * required.
- *
- * @param canScrollDown True if the view can scroll down further.
- */
- void notifyScrollabilityChange(boolean canScrollDown) {
- if (canScrollDown == mRequiringScrollToBottom) {
- // Already at the desired require-scroll state
- return;
- }
- if (canScrollDown) {
- if (!mEverScrolledToBottom) {
- postScrollStateChange(true);
- mRequiringScrollToBottom = true;
- }
- } else {
- postScrollStateChange(false);
- mRequiringScrollToBottom = false;
- mEverScrolledToBottom = true;
- }
- }
-
- private void postScrollStateChange(final boolean scrollNeeded) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mListener != null) {
- mListener.onRequireScrollStateChanged(scrollNeeded);
- }
+ }
+
+ private void postScrollStateChange(final boolean scrollNeeded) {
+ handler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (listener != null) {
+ listener.onRequireScrollStateChanged(scrollNeeded);
}
+ }
});
- }
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegate.java b/library/main/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegate.java
index 9e4d1cf..dcaa379 100644
--- a/library/main/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegate.java
+++ b/library/main/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegate.java
@@ -16,12 +16,10 @@
package com.android.setupwizardlib.template;
-import android.util.Log;
-import android.widget.ScrollView;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
+import android.util.Log;
+import android.widget.ScrollView;
import com.android.setupwizardlib.template.RequireScrollMixin.ScrollHandlingDelegate;
import com.android.setupwizardlib.view.BottomScrollView;
import com.android.setupwizardlib.view.BottomScrollView.BottomScrollListener;
@@ -31,51 +29,48 @@ import com.android.setupwizardlib.view.BottomScrollView.BottomScrollListener;
* notifies {@link RequireScrollMixin} about scrollability changes.
*/
public class ScrollViewScrollHandlingDelegate
- implements ScrollHandlingDelegate, BottomScrollListener {
+ implements ScrollHandlingDelegate, BottomScrollListener {
- private static final String TAG = "ScrollViewDelegate";
+ private static final String TAG = "ScrollViewDelegate";
- @NonNull
- private final RequireScrollMixin mRequireScrollMixin;
+ @NonNull private final RequireScrollMixin requireScrollMixin;
- @Nullable
- private final BottomScrollView mScrollView;
+ @Nullable private final BottomScrollView scrollView;
- public ScrollViewScrollHandlingDelegate(
- @NonNull RequireScrollMixin requireScrollMixin,
- @Nullable ScrollView scrollView) {
- mRequireScrollMixin = requireScrollMixin;
- if (scrollView instanceof BottomScrollView) {
- mScrollView = (BottomScrollView) scrollView;
- } else {
- Log.w(TAG, "Cannot set non-BottomScrollView. Found=" + scrollView);
- mScrollView = null;
- }
+ public ScrollViewScrollHandlingDelegate(
+ @NonNull RequireScrollMixin requireScrollMixin, @Nullable ScrollView scrollView) {
+ this.requireScrollMixin = requireScrollMixin;
+ if (scrollView instanceof BottomScrollView) {
+ this.scrollView = (BottomScrollView) scrollView;
+ } else {
+ Log.w(TAG, "Cannot set non-BottomScrollView. Found=" + scrollView);
+ this.scrollView = null;
}
+ }
- @Override
- public void onScrolledToBottom() {
- mRequireScrollMixin.notifyScrollabilityChange(false);
- }
+ @Override
+ public void onScrolledToBottom() {
+ requireScrollMixin.notifyScrollabilityChange(false);
+ }
- @Override
- public void onRequiresScroll() {
- mRequireScrollMixin.notifyScrollabilityChange(true);
- }
+ @Override
+ public void onRequiresScroll() {
+ requireScrollMixin.notifyScrollabilityChange(true);
+ }
- @Override
- public void startListening() {
- if (mScrollView != null) {
- mScrollView.setBottomScrollListener(this);
- } else {
- Log.w(TAG, "Cannot require scroll. Scroll view is null.");
- }
+ @Override
+ public void startListening() {
+ if (scrollView != null) {
+ scrollView.setBottomScrollListener(this);
+ } else {
+ Log.w(TAG, "Cannot require scroll. Scroll view is null.");
}
+ }
- @Override
- public void pageScrollDown() {
- if (mScrollView != null) {
- mScrollView.pageScroll(ScrollView.FOCUS_DOWN);
- }
+ @Override
+ public void pageScrollDown() {
+ if (scrollView != null) {
+ scrollView.pageScroll(ScrollView.FOCUS_DOWN);
}
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/util/DrawableLayoutDirectionHelper.java b/library/main/src/com/android/setupwizardlib/util/DrawableLayoutDirectionHelper.java
index b0afaba..8214415 100644
--- a/library/main/src/com/android/setupwizardlib/util/DrawableLayoutDirectionHelper.java
+++ b/library/main/src/com/android/setupwizardlib/util/DrawableLayoutDirectionHelper.java
@@ -23,59 +23,77 @@ import android.graphics.drawable.InsetDrawable;
import android.os.Build;
import android.view.View;
-/**
- * Provides convenience methods to handle drawable layout directions in different SDK versions.
- */
+/** Provides convenience methods to handle drawable layout directions in different SDK versions. */
public class DrawableLayoutDirectionHelper {
- /**
- * Creates an {@link android.graphics.drawable.InsetDrawable} according to the layout direction
- * of {@code view}.
- */
- @SuppressLint("InlinedApi") // Use of View.LAYOUT_DIRECTION_RTL is guarded by version check
- public static InsetDrawable createRelativeInsetDrawable(Drawable drawable,
- int insetStart, int insetTop, int insetEnd, int insetBottom, View view) {
- boolean isRtl = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
- && view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
- return createRelativeInsetDrawable(drawable, insetStart, insetTop, insetEnd, insetBottom,
- isRtl);
- }
+ /**
+ * Creates an {@link android.graphics.drawable.InsetDrawable} according to the layout direction of
+ * {@code view}.
+ */
+ @SuppressLint("InlinedApi") // Use of View.LAYOUT_DIRECTION_RTL is guarded by version check
+ public static InsetDrawable createRelativeInsetDrawable(
+ Drawable drawable, int insetStart, int insetTop, int insetEnd, int insetBottom, View view) {
+ boolean isRtl =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
+ && view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ return createRelativeInsetDrawable(
+ drawable, insetStart, insetTop, insetEnd, insetBottom, isRtl);
+ }
- /**
- * Creates an {@link android.graphics.drawable.InsetDrawable} according to the layout direction
- * of {@code context}.
- */
- @SuppressLint("InlinedApi") // Use of View.LAYOUT_DIRECTION_RTL is guarded by version check
- public static InsetDrawable createRelativeInsetDrawable(Drawable drawable,
- int insetStart, int insetTop, int insetEnd, int insetBottom, Context context) {
- boolean isRtl = false;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- final int layoutDirection =
- context.getResources().getConfiguration().getLayoutDirection();
- isRtl = layoutDirection == View.LAYOUT_DIRECTION_RTL;
- }
- return createRelativeInsetDrawable(drawable, insetStart, insetTop, insetEnd, insetBottom,
- isRtl);
+ /**
+ * Creates an {@link android.graphics.drawable.InsetDrawable} according to the layout direction of
+ * {@code context}.
+ */
+ @SuppressLint("InlinedApi") // Use of View.LAYOUT_DIRECTION_RTL is guarded by version check
+ public static InsetDrawable createRelativeInsetDrawable(
+ Drawable drawable,
+ int insetStart,
+ int insetTop,
+ int insetEnd,
+ int insetBottom,
+ Context context) {
+ boolean isRtl = false;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ final int layoutDirection = context.getResources().getConfiguration().getLayoutDirection();
+ isRtl = layoutDirection == View.LAYOUT_DIRECTION_RTL;
}
+ return createRelativeInsetDrawable(
+ drawable, insetStart, insetTop, insetEnd, insetBottom, isRtl);
+ }
- /**
- * Creates an {@link android.graphics.drawable.InsetDrawable} according to
- * {@code layoutDirection}.
- */
- @SuppressLint("InlinedApi") // Given layoutDirection will not be View.LAYOUT_DIRECTION_RTL if
- // SDK version doesn't support it.
- public static InsetDrawable createRelativeInsetDrawable(Drawable drawable,
- int insetStart, int insetTop, int insetEnd, int insetBottom, int layoutDirection) {
- return createRelativeInsetDrawable(drawable, insetStart, insetTop, insetEnd, insetBottom,
- layoutDirection == View.LAYOUT_DIRECTION_RTL);
- }
+ /**
+ * Creates an {@link android.graphics.drawable.InsetDrawable} according to {@code
+ * layoutDirection}.
+ */
+ @SuppressLint("InlinedApi") // Given layoutDirection will not be View.LAYOUT_DIRECTION_RTL if
+ // SDK version doesn't support it.
+ public static InsetDrawable createRelativeInsetDrawable(
+ Drawable drawable,
+ int insetStart,
+ int insetTop,
+ int insetEnd,
+ int insetBottom,
+ int layoutDirection) {
+ return createRelativeInsetDrawable(
+ drawable,
+ insetStart,
+ insetTop,
+ insetEnd,
+ insetBottom,
+ layoutDirection == View.LAYOUT_DIRECTION_RTL);
+ }
- private static InsetDrawable createRelativeInsetDrawable(Drawable drawable,
- int insetStart, int insetTop, int insetEnd, int insetBottom, boolean isRtl) {
- if (isRtl) {
- return new InsetDrawable(drawable, insetEnd, insetTop, insetStart, insetBottom);
- } else {
- return new InsetDrawable(drawable, insetStart, insetTop, insetEnd, insetBottom);
- }
+ private static InsetDrawable createRelativeInsetDrawable(
+ Drawable drawable,
+ int insetStart,
+ int insetTop,
+ int insetEnd,
+ int insetBottom,
+ boolean isRtl) {
+ if (isRtl) {
+ return new InsetDrawable(drawable, insetEnd, insetTop, insetStart, insetBottom);
+ } else {
+ return new InsetDrawable(drawable, insetStart, insetTop, insetEnd, insetBottom);
}
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/util/FallbackThemeWrapper.java b/library/main/src/com/android/setupwizardlib/util/FallbackThemeWrapper.java
index 2ec4f84..96f9162 100644
--- a/library/main/src/com/android/setupwizardlib/util/FallbackThemeWrapper.java
+++ b/library/main/src/com/android/setupwizardlib/util/FallbackThemeWrapper.java
@@ -18,37 +18,33 @@ package com.android.setupwizardlib.util;
import android.content.Context;
import android.content.res.Resources.Theme;
-import android.view.ContextThemeWrapper;
-
import androidx.annotation.StyleRes;
+import android.view.ContextThemeWrapper;
/**
- * Same as {@link ContextThemeWrapper}, but the base context's theme attributes take precedence
- * over the wrapper context's. This is used to provide default values for theme attributes
- * referenced in layouts, to remove the risk of crashing the client because of using the wrong
- * theme.
+ * Same as {@link ContextThemeWrapper}, but the base context's theme attributes take precedence over
+ * the wrapper context's. This is used to provide default values for theme attributes referenced in
+ * layouts, to remove the risk of crashing the client because of using the wrong theme.
*/
public class FallbackThemeWrapper extends ContextThemeWrapper {
- /**
- * Creates a new context wrapper with the specified theme.
- *
- * The specified theme will be applied as fallbacks to the base context's theme. Any attributes
- * defined in the base context's theme will retain their original values. Otherwise values in
- * {@code themeResId} will be used.
- *
- * @param base The base context.
- * @param themeResId The theme to use as fallback.
- */
- public FallbackThemeWrapper(Context base, @StyleRes int themeResId) {
- super(base, themeResId);
- }
+ /**
+ * Creates a new context wrapper with the specified theme.
+ *
+ * <p>The specified theme will be applied as fallbacks to the base context's theme. Any attributes
+ * defined in the base context's theme will retain their original values. Otherwise values in
+ * {@code themeResId} will be used.
+ *
+ * @param base The base context.
+ * @param themeResId The theme to use as fallback.
+ */
+ public FallbackThemeWrapper(Context base, @StyleRes int themeResId) {
+ super(base, themeResId);
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- protected void onApplyThemeResource(Theme theme, int resId, boolean first) {
- theme.applyStyle(resId, false /* force */);
- }
+ /** {@inheritDoc} */
+ @Override
+ protected void onApplyThemeResource(Theme theme, int resId, boolean first) {
+ theme.applyStyle(resId, false /* force */);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/util/Partner.java b/library/main/src/com/android/setupwizardlib/util/Partner.java
index 9eaedc3..ce782cb 100644
--- a/library/main/src/com/android/setupwizardlib/util/Partner.java
+++ b/library/main/src/com/android/setupwizardlib/util/Partner.java
@@ -26,14 +26,13 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
-import android.util.Log;
-
import androidx.annotation.AnyRes;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
+import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
-
+import android.util.Log;
import java.util.List;
/**
@@ -46,157 +45,156 @@ import java.util.List;
*/
public class Partner {
- private static final String TAG = "(SUW) Partner";
-
- /** Marker action used to discover partner */
- private static final String ACTION_PARTNER_CUSTOMIZATION =
- "com.android.setupwizard.action.PARTNER_CUSTOMIZATION";
-
- private static boolean sSearched = false;
- private static Partner sPartner;
-
- /**
- * Convenience to get a drawable from partner overlay, or if not available, the drawable from
- * the original context.
- *
- * @see #getResourceEntry(android.content.Context, int)
- */
- public static Drawable getDrawable(Context context, @DrawableRes int id) {
- final ResourceEntry entry = getResourceEntry(context, id);
- return entry.resources.getDrawable(entry.id);
+ private static final String TAG = "(SUW) Partner";
+
+ /** Marker action used to discover partner. */
+ private static final String ACTION_PARTNER_CUSTOMIZATION =
+ "com.android.setupwizard.action.PARTNER_CUSTOMIZATION";
+
+ private static boolean searched = false;
+ @Nullable private static Partner partner;
+
+ /**
+ * Gets a drawable from partner overlay, or if not available, the drawable from the original
+ * context.
+ *
+ * @see #getResourceEntry(android.content.Context, int)
+ */
+ public static Drawable getDrawable(Context context, @DrawableRes int id) {
+ final ResourceEntry entry = getResourceEntry(context, id);
+ return entry.resources.getDrawable(entry.id);
+ }
+
+ /**
+ * Gets a string from partner overlay, or if not available, the string from the original context.
+ *
+ * @see #getResourceEntry(android.content.Context, int)
+ */
+ public static String getString(Context context, @StringRes int id) {
+ final ResourceEntry entry = getResourceEntry(context, id);
+ return entry.resources.getString(entry.id);
+ }
+
+ /**
+ * Gets a color from partner overlay, or if not available, the color from the original context.
+ */
+ public static int getColor(Context context, @ColorRes int id) {
+ final ResourceEntry resourceEntry = getResourceEntry(context, id);
+ return resourceEntry.resources.getColor(resourceEntry.id);
+ }
+
+ /**
+ * Gets a CharSequence from partner overlay, or if not available, the text from the original
+ * context.
+ */
+ public static CharSequence getText(Context context, @StringRes int id) {
+ final ResourceEntry entry = getResourceEntry(context, id);
+ return entry.resources.getText(entry.id);
+ }
+
+ /**
+ * Finds an entry of resource in the overlay package provided by partners. It will first look for
+ * the resource in the overlay package, and if not available, will return the one in the original
+ * context.
+ *
+ * @return a ResourceEntry in the partner overlay's resources, if one is defined. Otherwise the
+ * resources from the original context is returned. Clients can then get the resource by
+ * {@code entry.resources.getString(entry.id)}, or other methods available in {@link
+ * android.content.res.Resources}.
+ */
+ public static ResourceEntry getResourceEntry(Context context, @AnyRes int id) {
+ final Partner partner = Partner.get(context);
+ if (partner != null) {
+ final Resources ourResources = context.getResources();
+ final String name = ourResources.getResourceEntryName(id);
+ final String type = ourResources.getResourceTypeName(id);
+ final int partnerId = partner.getIdentifier(name, type);
+ if (partnerId != 0) {
+ return new ResourceEntry(partner.resources, partnerId, true);
+ }
}
-
- /**
- * Convenience to get a string from partner overlay, or if not available, the string from the
- * original context.
- *
- * @see #getResourceEntry(android.content.Context, int)
- */
- public static String getString(Context context, @StringRes int id) {
- final ResourceEntry entry = getResourceEntry(context, id);
- return entry.resources.getString(entry.id);
- }
-
- /**
- * Convenience method to get color from partner overlay, or if not available, the color from
- * the original context.
- */
- public static int getColor(Context context, @ColorRes int id) {
- final ResourceEntry resourceEntry = getResourceEntry(context, id);
- return resourceEntry.resources.getColor(resourceEntry.id);
- }
-
- /**
- * Convenience method to get a CharSequence from partner overlay, or if not available, the text
- * from the original context.
- */
- public static CharSequence getText(Context context, @StringRes int id) {
- final ResourceEntry entry = getResourceEntry(context, id);
- return entry.resources.getText(entry.id);
- }
-
- /**
- * Find an entry of resource in the overlay package provided by partners. It will first look for
- * the resource in the overlay package, and if not available, will return the one in the
- * original context.
- *
- * @return a ResourceEntry in the partner overlay's resources, if one is defined. Otherwise the
- * resources from the original context is returned. Clients can then get the resource by
- * {@code entry.resources.getString(entry.id)}, or other methods available in
- * {@link android.content.res.Resources}.
- */
- public static ResourceEntry getResourceEntry(Context context, @AnyRes int id) {
- final Partner partner = Partner.get(context);
- if (partner != null) {
- final Resources ourResources = context.getResources();
- final String name = ourResources.getResourceEntryName(id);
- final String type = ourResources.getResourceTypeName(id);
- final int partnerId = partner.getIdentifier(name, type);
- if (partnerId != 0) {
- return new ResourceEntry(partner.mResources, partnerId, true);
- }
- }
- return new ResourceEntry(context.getResources(), id, false);
+ return new ResourceEntry(context.getResources(), id, false);
+ }
+
+ public static class ResourceEntry {
+ public Resources resources;
+ public int id;
+ public boolean isOverlay;
+
+ ResourceEntry(Resources resources, int id, boolean isOverlay) {
+ this.resources = resources;
+ this.id = id;
+ this.isOverlay = isOverlay;
}
-
- public static class ResourceEntry {
- public Resources resources;
- public int id;
- public boolean isOverlay;
-
- ResourceEntry(Resources resources, int id, boolean isOverlay) {
- this.resources = resources;
- this.id = id;
- this.isOverlay = isOverlay;
+ }
+
+ /**
+ * Finds and returns partner details, or {@code null} if none exists. A partner package is marked
+ * by a broadcast receiver declared in the manifest that handles the {@code
+ * com.android.setupwizard.action.PARTNER_CUSTOMIZATION} intent action. The overlay package must
+ * also be a system package.
+ */
+ public static synchronized Partner get(Context context) {
+ if (!searched) {
+ PackageManager pm = context.getPackageManager();
+ final Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION);
+ List<ResolveInfo> receivers;
+ if (VERSION.SDK_INT >= VERSION_CODES.N) {
+ receivers =
+ pm.queryBroadcastReceivers(
+ intent,
+ PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+ } else {
+ // On versions before N, direct boot doesn't exist. And the MATCH_SYSTEM_ONLY flag
+ // doesn't exist so we filter for system apps in code below.
+ receivers = pm.queryBroadcastReceivers(intent, 0);
+ }
+
+ for (ResolveInfo info : receivers) {
+ if (info.activityInfo == null) {
+ continue;
}
- }
-
- /**
- * Find and return partner details, or {@code null} if none exists. A partner package is marked
- * by a broadcast receiver declared in the manifest that handles the
- * {@code com.android.setupwizard.action.PARTNER_CUSTOMIZATION} intent action. The overlay
- * package must also be a system package.
- */
- public static synchronized Partner get(Context context) {
- if (!sSearched) {
- PackageManager pm = context.getPackageManager();
- final Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION);
- List<ResolveInfo> receivers;
- if (VERSION.SDK_INT >= VERSION_CODES.N) {
- receivers = pm.queryBroadcastReceivers(
- intent,
- PackageManager.MATCH_SYSTEM_ONLY
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- } else {
- // On versions before N, direct boot doesn't exist. And the MATCH_SYSTEM_ONLY flag
- // doesn't exist so we filter for system apps in code below.
- receivers = pm.queryBroadcastReceivers(intent, 0);
- }
-
- for (ResolveInfo info : receivers) {
- if (info.activityInfo == null) {
- continue;
- }
- final ApplicationInfo appInfo = info.activityInfo.applicationInfo;
- if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- try {
- final Resources res = pm.getResourcesForApplication(appInfo);
- sPartner = new Partner(appInfo.packageName, res);
- break;
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Failed to find resources for " + appInfo.packageName);
- }
- }
- }
- sSearched = true;
+ final ApplicationInfo appInfo = info.activityInfo.applicationInfo;
+ if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ try {
+ final Resources res = pm.getResourcesForApplication(appInfo);
+ partner = new Partner(appInfo.packageName, res);
+ break;
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Failed to find resources for " + appInfo.packageName);
+ }
}
- return sPartner;
- }
-
- @VisibleForTesting
- public static synchronized void resetForTesting() {
- sSearched = false;
- sPartner = null;
- }
-
- private final String mPackageName;
- private final Resources mResources;
-
- private Partner(String packageName, Resources res) {
- mPackageName = packageName;
- mResources = res;
- }
-
- public String getPackageName() {
- return mPackageName;
- }
-
- public Resources getResources() {
- return mResources;
- }
-
- public int getIdentifier(String name, String defType) {
- return mResources.getIdentifier(name, defType, mPackageName);
+ }
+ searched = true;
}
+ return partner;
+ }
+
+ @VisibleForTesting
+ public static synchronized void resetForTesting() {
+ searched = false;
+ partner = null;
+ }
+
+ private final String packageName;
+ private final Resources resources;
+
+ private Partner(String packageName, Resources res) {
+ this.packageName = packageName;
+ resources = res;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public Resources getResources() {
+ return resources;
+ }
+
+ public int getIdentifier(String name, String defType) {
+ return resources.getIdentifier(name, defType, packageName);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/util/ResultCodes.java b/library/main/src/com/android/setupwizardlib/util/ResultCodes.java
index a429e73..ea20139 100644
--- a/library/main/src/com/android/setupwizardlib/util/ResultCodes.java
+++ b/library/main/src/com/android/setupwizardlib/util/ResultCodes.java
@@ -20,9 +20,9 @@ import static android.app.Activity.RESULT_FIRST_USER;
public final class ResultCodes {
- public static final int RESULT_SKIP = RESULT_FIRST_USER;
- public static final int RESULT_RETRY = RESULT_FIRST_USER + 1;
- public static final int RESULT_ACTIVITY_NOT_FOUND = RESULT_FIRST_USER + 2;
+ public static final int RESULT_SKIP = RESULT_FIRST_USER;
+ public static final int RESULT_RETRY = RESULT_FIRST_USER + 1;
+ public static final int RESULT_ACTIVITY_NOT_FOUND = RESULT_FIRST_USER + 2;
- public static final int RESULT_FIRST_SETUP_USER = RESULT_FIRST_USER + 100;
+ public static final int RESULT_FIRST_SETUP_USER = RESULT_FIRST_USER + 100;
}
diff --git a/library/main/src/com/android/setupwizardlib/util/SystemBarHelper.java b/library/main/src/com/android/setupwizardlib/util/SystemBarHelper.java
index 7e3e885..42350cc 100644
--- a/library/main/src/com/android/setupwizardlib/util/SystemBarHelper.java
+++ b/library/main/src/com/android/setupwizardlib/util/SystemBarHelper.java
@@ -24,6 +24,7 @@ import android.content.res.TypedArray;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
+import androidx.annotation.RequiresPermission;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -31,331 +32,327 @@ import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
-import androidx.annotation.RequiresPermission;
-
/**
* A helper class to manage the system navigation bar and status bar. This will add various
* systemUiVisibility flags to the given Window or View to make them follow the Setup Wizard style.
*
- * When the useImmersiveMode intent extra is true, a screen in Setup Wizard should hide the system
- * bars using methods from this class. For Lollipop, {@link #hideSystemBars(android.view.Window)}
- * will completely hide the system navigation bar and change the status bar to transparent, and
- * layout the screen contents (usually the illustration) behind it.
+ * <p>When the useImmersiveMode intent extra is true, a screen in Setup Wizard should hide the
+ * system bars using methods from this class. For Lollipop, {@link
+ * #hideSystemBars(android.view.Window)} will completely hide the system navigation bar and change
+ * the status bar to transparent, and layout the screen contents (usually the illustration) behind
+ * it.
*/
public class SystemBarHelper {
- private static final String TAG = "SystemBarHelper";
-
- @SuppressLint("InlinedApi")
- private static final int DEFAULT_IMMERSIVE_FLAGS =
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-
- @SuppressLint("InlinedApi")
- private static final int DIALOG_IMMERSIVE_FLAGS =
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-
- /**
- * Needs to be equal to View.STATUS_BAR_DISABLE_BACK
- */
- private static final int STATUS_BAR_DISABLE_BACK = 0x00400000;
-
- /**
- * The maximum number of retries when peeking the decor view. When polling for the decor view,
- * waiting it to be installed, set a maximum number of retries.
- */
- private static final int PEEK_DECOR_VIEW_RETRIES = 3;
-
- /**
- * Hide the navigation bar for a dialog.
- *
- * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op.
- */
- public static void hideSystemBars(final Dialog dialog) {
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- final Window window = dialog.getWindow();
- temporarilyDisableDialogFocus(window);
- addVisibilityFlag(window, DIALOG_IMMERSIVE_FLAGS);
- addImmersiveFlagsToDecorView(window, DIALOG_IMMERSIVE_FLAGS);
-
- // Also set the navigation bar and status bar to transparent color. Note that this
- // doesn't work if android.R.boolean.config_enableTranslucentDecor is false.
- window.setNavigationBarColor(0);
- window.setStatusBarColor(0);
- }
+ private static final String TAG = "SystemBarHelper";
+
+ @SuppressLint("InlinedApi")
+ private static final int DEFAULT_IMMERSIVE_FLAGS =
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+
+ @SuppressLint("InlinedApi")
+ private static final int DIALOG_IMMERSIVE_FLAGS =
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+
+ /** Needs to be equal to View.STATUS_BAR_DISABLE_BACK */
+ private static final int STATUS_BAR_DISABLE_BACK = 0x00400000;
+
+ /**
+ * The maximum number of retries when peeking the decor view. When polling for the decor view,
+ * waiting it to be installed, set a maximum number of retries.
+ */
+ private static final int PEEK_DECOR_VIEW_RETRIES = 3;
+
+ /**
+ * Hide the navigation bar for a dialog.
+ *
+ * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op.
+ */
+ public static void hideSystemBars(final Dialog dialog) {
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ final Window window = dialog.getWindow();
+ temporarilyDisableDialogFocus(window);
+ addVisibilityFlag(window, DIALOG_IMMERSIVE_FLAGS);
+ addImmersiveFlagsToDecorView(window, DIALOG_IMMERSIVE_FLAGS);
+
+ // Also set the navigation bar and status bar to transparent color. Note that this
+ // doesn't work if android.R.boolean.config_enableTranslucentDecor is false.
+ window.setNavigationBarColor(0);
+ window.setStatusBarColor(0);
}
-
- /**
- * Hide the navigation bar, make the color of the status and navigation bars transparent, and
- * specify {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} flag so that the content is laid-out
- * behind the transparent status bar. This is commonly used with
- * {@link android.app.Activity#getWindow()} to make the navigation and status bars follow the
- * Setup Wizard style.
- *
- * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op.
- */
- public static void hideSystemBars(final Window window) {
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- addVisibilityFlag(window, DEFAULT_IMMERSIVE_FLAGS);
- addImmersiveFlagsToDecorView(window, DEFAULT_IMMERSIVE_FLAGS);
-
- // Also set the navigation bar and status bar to transparent color. Note that this
- // doesn't work if android.R.boolean.config_enableTranslucentDecor is false.
- window.setNavigationBarColor(0);
- window.setStatusBarColor(0);
- }
+ }
+
+ /**
+ * Hide the navigation bar, make the color of the status and navigation bars transparent, and
+ * specify {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} flag so that the content is laid-out
+ * behind the transparent status bar. This is commonly used with {@link
+ * android.app.Activity#getWindow()} to make the navigation and status bars follow the Setup
+ * Wizard style.
+ *
+ * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op.
+ */
+ public static void hideSystemBars(final Window window) {
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ addVisibilityFlag(window, DEFAULT_IMMERSIVE_FLAGS);
+ addImmersiveFlagsToDecorView(window, DEFAULT_IMMERSIVE_FLAGS);
+
+ // Also set the navigation bar and status bar to transparent color. Note that this
+ // doesn't work if android.R.boolean.config_enableTranslucentDecor is false.
+ window.setNavigationBarColor(0);
+ window.setStatusBarColor(0);
}
-
- /**
- * Revert the actions of hideSystemBars. Note that this will remove the system UI visibility
- * flags regardless of whether it is originally present. You should also manually reset the
- * navigation bar and status bar colors, as this method doesn't know what value to revert it to.
- */
- public static void showSystemBars(final Dialog dialog, final Context context) {
- showSystemBars(dialog.getWindow(), context);
+ }
+
+ /**
+ * Revert the actions of hideSystemBars. Note that this will remove the system UI visibility flags
+ * regardless of whether it is originally present. You should also manually reset the navigation
+ * bar and status bar colors, as this method doesn't know what value to revert it to.
+ */
+ public static void showSystemBars(final Dialog dialog, final Context context) {
+ showSystemBars(dialog.getWindow(), context);
+ }
+
+ /**
+ * Revert the actions of hideSystemBars. Note that this will remove the system UI visibility flags
+ * regardless of whether it is originally present. You should also manually reset the navigation
+ * bar and status bar colors, as this method doesn't know what value to revert it to.
+ */
+ public static void showSystemBars(final Window window, final Context context) {
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ removeVisibilityFlag(window, DEFAULT_IMMERSIVE_FLAGS);
+ removeImmersiveFlagsFromDecorView(window, DEFAULT_IMMERSIVE_FLAGS);
+
+ if (context != null) {
+ //noinspection AndroidLintInlinedApi
+ final TypedArray typedArray =
+ context.obtainStyledAttributes(
+ new int[] {android.R.attr.statusBarColor, android.R.attr.navigationBarColor});
+ final int statusBarColor = typedArray.getColor(0, 0);
+ final int navigationBarColor = typedArray.getColor(1, 0);
+ window.setStatusBarColor(statusBarColor);
+ window.setNavigationBarColor(navigationBarColor);
+ typedArray.recycle();
+ }
}
+ }
- /**
- * Revert the actions of hideSystemBars. Note that this will remove the system UI visibility
- * flags regardless of whether it is originally present. You should also manually reset the
- * navigation bar and status bar colors, as this method doesn't know what value to revert it to.
- */
- public static void showSystemBars(final Window window, final Context context) {
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- removeVisibilityFlag(window, DEFAULT_IMMERSIVE_FLAGS);
- removeImmersiveFlagsFromDecorView(window, DEFAULT_IMMERSIVE_FLAGS);
-
- if (context != null) {
- //noinspection AndroidLintInlinedApi
- final TypedArray typedArray = context.obtainStyledAttributes(new int[]{
- android.R.attr.statusBarColor, android.R.attr.navigationBarColor});
- final int statusBarColor = typedArray.getColor(0, 0);
- final int navigationBarColor = typedArray.getColor(1, 0);
- window.setStatusBarColor(statusBarColor);
- window.setNavigationBarColor(navigationBarColor);
- typedArray.recycle();
- }
- }
+ /** Convenience method to add a visibility flag in addition to the existing ones. */
+ public static void addVisibilityFlag(final View view, final int flag) {
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ final int vis = view.getSystemUiVisibility();
+ view.setSystemUiVisibility(vis | flag);
}
-
- /**
- * Convenience method to add a visibility flag in addition to the existing ones.
- */
- public static void addVisibilityFlag(final View view, final int flag) {
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- final int vis = view.getSystemUiVisibility();
- view.setSystemUiVisibility(vis | flag);
- }
+ }
+
+ /** Convenience method to add a visibility flag in addition to the existing ones. */
+ public static void addVisibilityFlag(final Window window, final int flag) {
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ WindowManager.LayoutParams attrs = window.getAttributes();
+ attrs.systemUiVisibility |= flag;
+ window.setAttributes(attrs);
}
-
- /**
- * Convenience method to add a visibility flag in addition to the existing ones.
- */
- public static void addVisibilityFlag(final Window window, final int flag) {
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- WindowManager.LayoutParams attrs = window.getAttributes();
- attrs.systemUiVisibility |= flag;
- window.setAttributes(attrs);
- }
+ }
+
+ /**
+ * Convenience method to remove a visibility flag from the view, leaving other flags that are not
+ * specified intact.
+ */
+ public static void removeVisibilityFlag(final View view, final int flag) {
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ final int vis = view.getSystemUiVisibility();
+ view.setSystemUiVisibility(vis & ~flag);
}
-
- /**
- * Convenience method to remove a visibility flag from the view, leaving other flags that are
- * not specified intact.
- */
- public static void removeVisibilityFlag(final View view, final int flag) {
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- final int vis = view.getSystemUiVisibility();
- view.setSystemUiVisibility(vis & ~flag);
- }
+ }
+
+ /**
+ * Convenience method to remove a visibility flag from the window, leaving other flags that are
+ * not specified intact.
+ */
+ public static void removeVisibilityFlag(final Window window, final int flag) {
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ WindowManager.LayoutParams attrs = window.getAttributes();
+ attrs.systemUiVisibility &= ~flag;
+ window.setAttributes(attrs);
}
-
- /**
- * Convenience method to remove a visibility flag from the window, leaving other flags that are
- * not specified intact.
- */
- public static void removeVisibilityFlag(final Window window, final int flag) {
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- WindowManager.LayoutParams attrs = window.getAttributes();
- attrs.systemUiVisibility &= ~flag;
- window.setAttributes(attrs);
- }
+ }
+
+ /**
+ * Sets whether the back button on the software navigation bar is visible. This only works if you
+ * have the STATUS_BAR permission. Otherwise framework will filter out this flag and this method
+ * call will not have any effect.
+ *
+ * <p>IMPORTANT: Do not assume that users have no way to go back when the back button is hidden.
+ * Many devices have physical back buttons, and accessibility services like TalkBack may have
+ * gestures mapped to back. Please use onBackPressed, onKeyDown, or other similar ways to make
+ * sure back button events are still handled (or ignored) properly.
+ */
+ @RequiresPermission("android.permission.STATUS_BAR")
+ public static void setBackButtonVisible(final Window window, final boolean visible) {
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ if (visible) {
+ removeVisibilityFlag(window, STATUS_BAR_DISABLE_BACK);
+ removeImmersiveFlagsFromDecorView(window, STATUS_BAR_DISABLE_BACK);
+ } else {
+ addVisibilityFlag(window, STATUS_BAR_DISABLE_BACK);
+ addImmersiveFlagsToDecorView(window, STATUS_BAR_DISABLE_BACK);
+ }
}
-
- /**
- * Sets whether the back button on the software navigation bar is visible. This only works if
- * you have the STATUS_BAR permission. Otherwise framework will filter out this flag and this
- * method call will not have any effect.
- *
- * <p>IMPORTANT: Do not assume that users have no way to go back when the back button is hidden.
- * Many devices have physical back buttons, and accessibility services like TalkBack may have
- * gestures mapped to back. Please use onBackPressed, onKeyDown, or other similar ways to
- * make sure back button events are still handled (or ignored) properly.
- */
- @RequiresPermission("android.permission.STATUS_BAR")
- public static void setBackButtonVisible(final Window window, final boolean visible) {
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- if (visible) {
- removeVisibilityFlag(window, STATUS_BAR_DISABLE_BACK);
- removeImmersiveFlagsFromDecorView(window, STATUS_BAR_DISABLE_BACK);
- } else {
- addVisibilityFlag(window, STATUS_BAR_DISABLE_BACK);
- addImmersiveFlagsToDecorView(window, STATUS_BAR_DISABLE_BACK);
- }
- }
+ }
+
+ /**
+ * Set a view to be resized when the keyboard is shown. This will set the bottom margin of the
+ * view to be immediately above the keyboard, and assumes that the view sits immediately above the
+ * navigation bar.
+ *
+ * <p>Note that you must set {@link android.R.attr#windowSoftInputMode} to {@code adjustResize}
+ * for this class to work. Otherwise window insets are not dispatched and this method will have no
+ * effect.
+ *
+ * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op.
+ *
+ * @param view The view to be resized when the keyboard is shown.
+ */
+ public static void setImeInsetView(final View view) {
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ view.setOnApplyWindowInsetsListener(new WindowInsetsListener());
}
-
- /**
- * Set a view to be resized when the keyboard is shown. This will set the bottom margin of the
- * view to be immediately above the keyboard, and assumes that the view sits immediately above
- * the navigation bar.
- *
- * <p>Note that you must set {@link android.R.attr#windowSoftInputMode} to {@code adjustResize}
- * for this class to work. Otherwise window insets are not dispatched and this method will have
- * no effect.
- *
- * <p>This will only take effect in versions Lollipop or above. Otherwise this is a no-op.
- *
- * @param view The view to be resized when the keyboard is shown.
- */
- public static void setImeInsetView(final View view) {
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- view.setOnApplyWindowInsetsListener(new WindowInsetsListener());
- }
- }
-
- /**
- * Add the specified immersive flags to the decor view of the window, because
- * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} only takes effect when it is added to a view
- * instead of the window.
- */
- @TargetApi(VERSION_CODES.HONEYCOMB)
- private static void addImmersiveFlagsToDecorView(final Window window, final int vis) {
- getDecorView(window, new OnDecorViewInstalledListener() {
- @Override
- public void onDecorViewInstalled(View decorView) {
- addVisibilityFlag(decorView, vis);
- }
+ }
+
+ /**
+ * Add the specified immersive flags to the decor view of the window, because {@link
+ * View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} only takes effect when it is added to a view instead of
+ * the window.
+ */
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ private static void addImmersiveFlagsToDecorView(final Window window, final int vis) {
+ getDecorView(
+ window,
+ new OnDecorViewInstalledListener() {
+ @Override
+ public void onDecorViewInstalled(View decorView) {
+ addVisibilityFlag(decorView, vis);
+ }
});
- }
-
- @TargetApi(VERSION_CODES.HONEYCOMB)
- private static void removeImmersiveFlagsFromDecorView(final Window window, final int vis) {
- getDecorView(window, new OnDecorViewInstalledListener() {
- @Override
- public void onDecorViewInstalled(View decorView) {
- removeVisibilityFlag(decorView, vis);
- }
+ }
+
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ private static void removeImmersiveFlagsFromDecorView(final Window window, final int vis) {
+ getDecorView(
+ window,
+ new OnDecorViewInstalledListener() {
+ @Override
+ public void onDecorViewInstalled(View decorView) {
+ removeVisibilityFlag(decorView, vis);
+ }
});
- }
-
- private static void getDecorView(Window window, OnDecorViewInstalledListener callback) {
- new DecorViewFinder().getDecorView(window, callback, PEEK_DECOR_VIEW_RETRIES);
- }
-
- private static class DecorViewFinder {
-
- private final Handler mHandler = new Handler();
- private Window mWindow;
- private int mRetries;
- private OnDecorViewInstalledListener mCallback;
-
- private Runnable mCheckDecorViewRunnable = new Runnable() {
- @Override
- public void run() {
- // Use peekDecorView instead of getDecorView so that clients can still set window
- // features after calling this method.
- final View decorView = mWindow.peekDecorView();
- if (decorView != null) {
- mCallback.onDecorViewInstalled(decorView);
- } else {
- mRetries--;
- if (mRetries >= 0) {
- // If the decor view is not installed yet, try again in the next loop.
- mHandler.post(mCheckDecorViewRunnable);
- } else {
- Log.w(TAG, "Cannot get decor view of window: " + mWindow);
- }
- }
+ }
+
+ private static void getDecorView(Window window, OnDecorViewInstalledListener callback) {
+ new DecorViewFinder().getDecorView(window, callback, PEEK_DECOR_VIEW_RETRIES);
+ }
+
+ private static class DecorViewFinder {
+
+ private final Handler handler = new Handler();
+ private Window window;
+ private int retries;
+ private OnDecorViewInstalledListener callback;
+
+ private final Runnable checkDecorViewRunnable =
+ new Runnable() {
+ @Override
+ public void run() {
+ // Use peekDecorView instead of getDecorView so that clients can still set window
+ // features after calling this method.
+ final View decorView = window.peekDecorView();
+ if (decorView != null) {
+ callback.onDecorViewInstalled(decorView);
+ } else {
+ retries--;
+ if (retries >= 0) {
+ // If the decor view is not installed yet, try again in the next loop.
+ handler.post(checkDecorViewRunnable);
+ } else {
+ Log.w(TAG, "Cannot get decor view of window: " + window);
+ }
}
+ }
};
- public void getDecorView(Window window, OnDecorViewInstalledListener callback,
- int retries) {
- mWindow = window;
- mRetries = retries;
- mCallback = callback;
- mCheckDecorViewRunnable.run();
- }
+ public void getDecorView(Window window, OnDecorViewInstalledListener callback, int retries) {
+ this.window = window;
+ this.retries = retries;
+ this.callback = callback;
+ checkDecorViewRunnable.run();
}
-
- private interface OnDecorViewInstalledListener {
-
- void onDecorViewInstalled(View decorView);
- }
-
- /**
- * Apply a hack to temporarily set the window to not focusable, so that the navigation bar
- * will not show up during the transition.
- */
- private static void temporarilyDisableDialogFocus(final Window window) {
- window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
- // Add the SOFT_INPUT_IS_FORWARD_NAVIGATION_FLAG. This is normally done by the system when
- // FLAG_NOT_FOCUSABLE is not set. Setting this flag allows IME to be shown automatically
- // if the dialog has editable text fields.
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION);
- new Handler().post(new Runnable() {
- @Override
- public void run() {
+ }
+
+ private interface OnDecorViewInstalledListener {
+
+ void onDecorViewInstalled(View decorView);
+ }
+
+ /**
+ * Apply a hack to temporarily set the window to not focusable, so that the navigation bar will
+ * not show up during the transition.
+ */
+ private static void temporarilyDisableDialogFocus(final Window window) {
+ window.setFlags(
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+ // Add the SOFT_INPUT_IS_FORWARD_NAVIGATION_FLAG. This is normally done by the system when
+ // FLAG_NOT_FOCUSABLE is not set. Setting this flag allows IME to be shown automatically
+ // if the dialog has editable text fields.
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION);
+ new Handler()
+ .post(
+ new Runnable() {
+ @Override
+ public void run() {
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
- }
- });
+ }
+ });
+ }
+
+ @TargetApi(VERSION_CODES.LOLLIPOP)
+ private static class WindowInsetsListener implements View.OnApplyWindowInsetsListener {
+ private int bottomOffset;
+ private boolean hasCalculatedBottomOffset = false;
+
+ @Override
+ public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
+ if (!hasCalculatedBottomOffset) {
+ bottomOffset = getBottomDistance(view);
+ hasCalculatedBottomOffset = true;
+ }
+
+ int bottomInset = insets.getSystemWindowInsetBottom();
+
+ final int bottomMargin = Math.max(insets.getSystemWindowInsetBottom() - bottomOffset, 0);
+
+ final ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
+ // Check that we have enough space to apply the bottom margins before applying it.
+ // Otherwise the framework may think that the view is empty and exclude it from layout.
+ if (bottomMargin < lp.bottomMargin + view.getHeight()) {
+ lp.setMargins(lp.leftMargin, lp.topMargin, lp.rightMargin, bottomMargin);
+ view.setLayoutParams(lp);
+ bottomInset = 0;
+ }
+
+ return insets.replaceSystemWindowInsets(
+ insets.getSystemWindowInsetLeft(),
+ insets.getSystemWindowInsetTop(),
+ insets.getSystemWindowInsetRight(),
+ bottomInset);
}
+ }
- @TargetApi(VERSION_CODES.LOLLIPOP)
- private static class WindowInsetsListener implements View.OnApplyWindowInsetsListener {
- private int mBottomOffset;
- private boolean mHasCalculatedBottomOffset = false;
-
- @Override
- public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
- if (!mHasCalculatedBottomOffset) {
- mBottomOffset = getBottomDistance(view);
- mHasCalculatedBottomOffset = true;
- }
-
- int bottomInset = insets.getSystemWindowInsetBottom();
-
- final int bottomMargin = Math.max(
- insets.getSystemWindowInsetBottom() - mBottomOffset, 0);
-
- final ViewGroup.MarginLayoutParams lp =
- (ViewGroup.MarginLayoutParams) view.getLayoutParams();
- // Check that we have enough space to apply the bottom margins before applying it.
- // Otherwise the framework may think that the view is empty and exclude it from layout.
- if (bottomMargin < lp.bottomMargin + view.getHeight()) {
- lp.setMargins(lp.leftMargin, lp.topMargin, lp.rightMargin, bottomMargin);
- view.setLayoutParams(lp);
- bottomInset = 0;
- }
-
-
- return insets.replaceSystemWindowInsets(
- insets.getSystemWindowInsetLeft(),
- insets.getSystemWindowInsetTop(),
- insets.getSystemWindowInsetRight(),
- bottomInset
- );
- }
- }
-
- private static int getBottomDistance(View view) {
- int[] coords = new int[2];
- view.getLocationInWindow(coords);
- return view.getRootView().getHeight() - coords[1] - view.getHeight();
- }
+ private static int getBottomDistance(View view) {
+ int[] coords = new int[2];
+ view.getLocationInWindow(coords);
+ return view.getRootView().getHeight() - coords[1] - view.getHeight();
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/util/ThemeResolver.java b/library/main/src/com/android/setupwizardlib/util/ThemeResolver.java
new file mode 100644
index 0000000..14fdc85
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/util/ThemeResolver.java
@@ -0,0 +1,219 @@
+package com.android.setupwizardlib.util;
+
+import android.app.Activity;
+import android.content.Intent;
+import androidx.annotation.Nullable;
+import androidx.annotation.StyleRes;
+import com.android.setupwizardlib.R;
+
+/**
+ * A resolver to resolve the theme from a string or an activity intent, setting options like the
+ * default theme and the oldest supported theme. Apps can share the resolver across the entire
+ * process by calling {@link #setDefault(ThemeResolver)} in {@link
+ * android.app.Application#onCreate()}. If an app needs more granular sharing of the theme default
+ * values, additional instances of {@link ThemeResolver} can be created using the builder.
+ */
+public class ThemeResolver {
+ @StyleRes private final int defaultTheme;
+ @Nullable private final String oldestSupportedTheme;
+ private final boolean useDayNight;
+
+ @Nullable private static ThemeResolver defaultResolver;
+
+ /**
+ * Sets the default instance used for the whole process. Can be null to reset the default to the
+ * preset one.
+ */
+ public static void setDefault(@Nullable ThemeResolver resolver) {
+ defaultResolver = resolver;
+ }
+
+ /**
+ * Returns the default instance, which can be changed using {@link #setDefault(ThemeResolver)}.
+ */
+ public static ThemeResolver getDefault() {
+ if (defaultResolver == null) {
+ defaultResolver =
+ new ThemeResolver.Builder()
+ .setDefaultTheme(R.style.SuwThemeGlif_DayNight)
+ .setUseDayNight(true)
+ .build();
+ }
+ return defaultResolver;
+ }
+
+ private ThemeResolver(
+ int defaultTheme, @Nullable String oldestSupportedTheme, boolean useDayNight) {
+ this.defaultTheme = defaultTheme;
+ this.oldestSupportedTheme = oldestSupportedTheme;
+ this.useDayNight = useDayNight;
+ }
+
+ /**
+ * Returns the style for the theme specified in the intent extra. If the specified string theme is
+ * older than the oldest supported theme, the default will be returned instead. Note that the
+ * default theme is returned without processing -- it may not be a DayNight theme even if {@link
+ * #useDayNight} is true.
+ */
+ @StyleRes
+ public int resolve(Intent intent) {
+ return resolve(
+ intent.getStringExtra(WizardManagerHelper.EXTRA_THEME),
+ /* suppressDayNight= */ WizardManagerHelper.isSetupWizardIntent(intent));
+ }
+
+ /**
+ * Returns the style for the given string theme. If the specified string theme is older than the
+ * oldest supported theme, the default will be returned instead. Note that the default theme is
+ * returned without processing -- it may not be a DayNight theme even if {@link #useDayNight} is
+ * true.
+ */
+ @StyleRes
+ public int resolve(@Nullable String theme) {
+ return resolve(theme, /* suppressDayNight= */ false);
+ }
+
+ @StyleRes
+ private int resolve(@Nullable String theme, boolean suppressDayNight) {
+ int themeResource =
+ useDayNight && !suppressDayNight ? getDayNightThemeRes(theme) : getThemeRes(theme);
+ if (themeResource == 0) {
+ return defaultTheme;
+ }
+
+ if (oldestSupportedTheme != null && compareThemes(theme, oldestSupportedTheme) < 0) {
+ return defaultTheme;
+ }
+ return themeResource;
+ }
+
+ /** Reads the theme from the intent, and applies the resolved theme to the activity. */
+ public void applyTheme(Activity activity) {
+ activity.setTheme(resolve(activity.getIntent()));
+ }
+
+ /**
+ * Returns the corresponding DayNight theme resource ID for the given string theme. DayNight
+ * themes are themes that will be either light or dark depending on the system setting. For
+ * example, the string {@link WizardManagerHelper#THEME_GLIF_LIGHT} will return
+ * {@code @style/SuwThemeGlif.DayNight}.
+ */
+ @StyleRes
+ private static int getDayNightThemeRes(@Nullable String theme) {
+ if (theme != null) {
+ switch (theme) {
+ case WizardManagerHelper.THEME_GLIF_V3_LIGHT:
+ case WizardManagerHelper.THEME_GLIF_V3:
+ return R.style.SuwThemeGlifV3_DayNight;
+ case WizardManagerHelper.THEME_GLIF_V2_LIGHT:
+ case WizardManagerHelper.THEME_GLIF_V2:
+ return R.style.SuwThemeGlifV2_DayNight;
+ case WizardManagerHelper.THEME_GLIF_LIGHT:
+ case WizardManagerHelper.THEME_GLIF:
+ return R.style.SuwThemeGlif_DayNight;
+ case WizardManagerHelper.THEME_MATERIAL_LIGHT:
+ case WizardManagerHelper.THEME_MATERIAL:
+ return R.style.SuwThemeMaterial_DayNight;
+ default:
+ // fall through
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the theme resource ID for the given string theme. For example, the string {@link
+ * WizardManagerHelper#THEME_GLIF_LIGHT} will return {@code @style/SuwThemeGlif.Light}.
+ */
+ @StyleRes
+ private static int getThemeRes(@Nullable String theme) {
+ if (theme != null) {
+ switch (theme) {
+ case WizardManagerHelper.THEME_GLIF_V3_LIGHT:
+ return R.style.SuwThemeGlifV3_Light;
+ case WizardManagerHelper.THEME_GLIF_V3:
+ return R.style.SuwThemeGlifV3;
+ case WizardManagerHelper.THEME_GLIF_V2_LIGHT:
+ return R.style.SuwThemeGlifV2_Light;
+ case WizardManagerHelper.THEME_GLIF_V2:
+ return R.style.SuwThemeGlifV2;
+ case WizardManagerHelper.THEME_GLIF_LIGHT:
+ return R.style.SuwThemeGlif_Light;
+ case WizardManagerHelper.THEME_GLIF:
+ return R.style.SuwThemeGlif;
+ case WizardManagerHelper.THEME_MATERIAL_LIGHT:
+ return R.style.SuwThemeMaterial_Light;
+ case WizardManagerHelper.THEME_MATERIAL:
+ return R.style.SuwThemeMaterial;
+ default:
+ // fall through
+ }
+ }
+ return 0;
+ }
+
+ /** Compares whether the versions of {@code theme1} and {@code theme2} to check which is newer. */
+ private static int compareThemes(String theme1, String theme2) {
+ return Integer.valueOf(getThemeVersion(theme1)).compareTo(getThemeVersion(theme2));
+ }
+
+ /**
+ * Returns the version of the theme. The absolute number of the theme version is not defined, but
+ * a larger number in the version indicates a newer theme.
+ */
+ private static int getThemeVersion(String theme) {
+ if (theme != null) {
+ switch (theme) {
+ case WizardManagerHelper.THEME_GLIF_V3_LIGHT:
+ case WizardManagerHelper.THEME_GLIF_V3:
+ return 4;
+ case WizardManagerHelper.THEME_GLIF_V2_LIGHT:
+ case WizardManagerHelper.THEME_GLIF_V2:
+ return 3;
+ case WizardManagerHelper.THEME_GLIF_LIGHT:
+ case WizardManagerHelper.THEME_GLIF:
+ return 2;
+ case WizardManagerHelper.THEME_MATERIAL_LIGHT:
+ case WizardManagerHelper.THEME_MATERIAL:
+ return 1;
+ default:
+ // fall through
+ }
+ }
+ return -1;
+ }
+
+ /** Builder class for {@link ThemeResolver}. */
+ public static class Builder {
+ @StyleRes private int defaultTheme = R.style.SuwThemeGlif_DayNight;
+ @Nullable private String oldestSupportedTheme = null;
+ private boolean useDayNight = true;
+
+ public Builder() {}
+
+ public Builder(ThemeResolver themeResolver) {
+ this.defaultTheme = themeResolver.defaultTheme;
+ this.oldestSupportedTheme = themeResolver.oldestSupportedTheme;
+ this.useDayNight = themeResolver.useDayNight;
+ }
+
+ public Builder setDefaultTheme(@StyleRes int defaultTheme) {
+ this.defaultTheme = defaultTheme;
+ return this;
+ }
+
+ public Builder setOldestSupportedTheme(String oldestSupportedTheme) {
+ this.oldestSupportedTheme = oldestSupportedTheme;
+ return this;
+ }
+
+ public Builder setUseDayNight(boolean useDayNight) {
+ this.useDayNight = useDayNight;
+ return this;
+ }
+
+ public ThemeResolver build() {
+ return new ThemeResolver(defaultTheme, oldestSupportedTheme, useDayNight);
+ }
+ }
+}
diff --git a/library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java b/library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java
index 0628192..4d75c78 100644
--- a/library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java
+++ b/library/main/src/com/android/setupwizardlib/util/WizardManagerHelper.java
@@ -16,314 +16,390 @@
package com.android.setupwizardlib.util;
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources.Theme;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.provider.Settings;
-
+import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
-
-import com.android.setupwizardlib.R;
-
import java.util.Arrays;
+/**
+ * Helper to interact with Wizard Manager in setup wizard, which should be used when a screen is
+ * shown inside the setup flow. This includes things like parsing extras passed by Wizard Manager,
+ * and invoking Wizard Manager to start the next action.
+ */
public class WizardManagerHelper {
- private static final String ACTION_NEXT = "com.android.wizard.NEXT";
-
- // EXTRA_SCRIPT_URI and EXTRA_ACTION_ID are used in setup wizard in versions before M and are
- // kept for backwards compatibility.
- @VisibleForTesting
- static final String EXTRA_SCRIPT_URI = "scriptUri";
- @VisibleForTesting
- static final String EXTRA_ACTION_ID = "actionId";
-
- @VisibleForTesting
- static final String EXTRA_WIZARD_BUNDLE = "wizardBundle";
- private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
- @VisibleForTesting
- static final String EXTRA_IS_FIRST_RUN = "firstRun";
- @VisibleForTesting
- static final String EXTRA_IS_DEFERRED_SETUP = "deferredSetup";
- @VisibleForTesting
- static final String EXTRA_IS_PRE_DEFERRED_SETUP = "preDeferredSetup";
-
- public static final String EXTRA_THEME = "theme";
- public static final String EXTRA_USE_IMMERSIVE_MODE = "useImmersiveMode";
-
- public static final String SETTINGS_GLOBAL_DEVICE_PROVISIONED = "device_provisioned";
- public static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete";
-
- public static final String THEME_HOLO = "holo";
- public static final String THEME_HOLO_LIGHT = "holo_light";
- public static final String THEME_MATERIAL = "material";
- public static final String THEME_MATERIAL_LIGHT = "material_light";
-
- /**
- * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the
- * theme used in setup wizard for Nougat MR1.
- */
- public static final String THEME_GLIF = "glif";
-
- /**
- * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in
- * setup wizard for Nougat MR1.
- */
- public static final String THEME_GLIF_LIGHT = "glif_light";
-
- /**
- * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the
- * theme used in setup wizard for O DR.
- */
- public static final String THEME_GLIF_V2 = "glif_v2";
-
- /**
- * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in
- * setup wizard for O DR.
- */
- public static final String THEME_GLIF_V2_LIGHT = "glif_v2_light";
-
- /**
- * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the
- * theme used in setup wizard for P.
- */
- public static final String THEME_GLIF_V3 = "glif_v3";
-
- /**
- * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in
- * setup wizard for P.
- */
- public static final String THEME_GLIF_V3_LIGHT = "glif_v3_light";
-
- /**
- * Get an intent that will invoke the next step of setup wizard.
- *
- * @param originalIntent The original intent that was used to start the step, usually via
- * {@link android.app.Activity#getIntent()}.
- * @param resultCode The result code of the step. See {@link ResultCodes}.
- * @return A new intent that can be used with
- * {@link android.app.Activity#startActivityForResult(Intent, int)} to start the next
- * step of the setup flow.
- */
- public static Intent getNextIntent(Intent originalIntent, int resultCode) {
- return getNextIntent(originalIntent, resultCode, null);
- }
-
- /**
- * Get an intent that will invoke the next step of setup wizard.
- *
- * @param originalIntent The original intent that was used to start the step, usually via
- * {@link android.app.Activity#getIntent()}.
- * @param resultCode The result code of the step. See {@link ResultCodes}.
- * @param data An intent containing extra result data.
- * @return A new intent that can be used with
- * {@link android.app.Activity#startActivityForResult(Intent, int)} to start the next
- * step of the setup flow.
- */
- public static Intent getNextIntent(Intent originalIntent, int resultCode, Intent data) {
- Intent intent = new Intent(ACTION_NEXT);
- copyWizardManagerExtras(originalIntent, intent);
- intent.putExtra(EXTRA_RESULT_CODE, resultCode);
- if (data != null && data.getExtras() != null) {
- intent.putExtras(data.getExtras());
- }
- intent.putExtra(EXTRA_THEME, originalIntent.getStringExtra(EXTRA_THEME));
-
- return intent;
- }
-
- /**
- * Copy the internal extras used by setup wizard from one intent to another. For low-level use
- * only, such as when using {@link Intent#FLAG_ACTIVITY_FORWARD_RESULT} to relay to another
- * intent.
- *
- * @param srcIntent Intent to get the wizard manager extras from.
- * @param dstIntent Intent to copy the wizard manager extras to.
- */
- public static void copyWizardManagerExtras(Intent srcIntent, Intent dstIntent) {
- dstIntent.putExtra(EXTRA_WIZARD_BUNDLE, srcIntent.getBundleExtra(EXTRA_WIZARD_BUNDLE));
- for (String key : Arrays.asList(
- EXTRA_IS_FIRST_RUN, EXTRA_IS_DEFERRED_SETUP, EXTRA_IS_PRE_DEFERRED_SETUP)) {
- dstIntent.putExtra(key, srcIntent.getBooleanExtra(key, false));
- }
-
- for (String key : Arrays.asList(EXTRA_THEME, EXTRA_SCRIPT_URI, EXTRA_ACTION_ID)) {
- dstIntent.putExtra(key, srcIntent.getStringExtra(key));
- }
- }
-
- /**
- * Check whether an intent is intended to be used within the setup wizard flow.
- *
- * @param intent The intent to be checked, usually from
- * {@link android.app.Activity#getIntent()}.
- * @return true if the intent passed in was intended to be used with setup wizard.
- */
- public static boolean isSetupWizardIntent(Intent intent) {
- return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false);
+ private static final String ACTION_NEXT = "com.android.wizard.NEXT";
+
+ // EXTRA_SCRIPT_URI and EXTRA_ACTION_ID are used in setup wizard in versions before M and are
+ // kept for backwards compatibility.
+ @VisibleForTesting static final String EXTRA_SCRIPT_URI = "scriptUri";
+ @VisibleForTesting static final String EXTRA_ACTION_ID = "actionId";
+
+ @VisibleForTesting static final String EXTRA_WIZARD_BUNDLE = "wizardBundle";
+ private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
+ @VisibleForTesting static final String EXTRA_IS_FIRST_RUN = "firstRun";
+ @VisibleForTesting static final String EXTRA_IS_DEFERRED_SETUP = "deferredSetup";
+ @VisibleForTesting static final String EXTRA_IS_PRE_DEFERRED_SETUP = "preDeferredSetup";
+ @VisibleForTesting public static final String EXTRA_IS_SETUP_FLOW = "isSetupFlow";
+
+ public static final String EXTRA_THEME = "theme";
+ public static final String EXTRA_USE_IMMERSIVE_MODE = "useImmersiveMode";
+
+ public static final String SETTINGS_GLOBAL_DEVICE_PROVISIONED = "device_provisioned";
+ public static final String SETTINGS_SECURE_USER_SETUP_COMPLETE = "user_setup_complete";
+
+ public static final String THEME_HOLO = "holo";
+ public static final String THEME_HOLO_LIGHT = "holo_light";
+ public static final String THEME_MATERIAL = "material";
+ public static final String THEME_MATERIAL_LIGHT = "material_light";
+
+ /**
+ * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the theme
+ * used in setup wizard for Nougat MR1.
+ */
+ public static final String THEME_GLIF = "glif";
+
+ /**
+ * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in
+ * setup wizard for Nougat MR1.
+ */
+ public static final String THEME_GLIF_LIGHT = "glif_light";
+
+ /**
+ * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the theme
+ * used in setup wizard for O DR.
+ */
+ public static final String THEME_GLIF_V2 = "glif_v2";
+
+ /**
+ * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in
+ * setup wizard for O DR.
+ */
+ public static final String THEME_GLIF_V2_LIGHT = "glif_v2_light";
+
+ /**
+ * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the dark variant of the theme
+ * used in setup wizard for P.
+ */
+ public static final String THEME_GLIF_V3 = "glif_v3";
+
+ /**
+ * Passed in a setup wizard intent as {@link #EXTRA_THEME}. This is the default theme used in
+ * setup wizard for P.
+ */
+ public static final String THEME_GLIF_V3_LIGHT = "glif_v3_light";
+
+ /**
+ * Get an intent that will invoke the next step of setup wizard.
+ *
+ * @param originalIntent The original intent that was used to start the step, usually via {@link
+ * android.app.Activity#getIntent()}.
+ * @param resultCode The result code of the step. See {@link ResultCodes}.
+ * @return A new intent that can be used with {@link
+ * android.app.Activity#startActivityForResult(Intent, int)} to start the next step of the
+ * setup flow.
+ */
+ public static Intent getNextIntent(Intent originalIntent, int resultCode) {
+ return getNextIntent(originalIntent, resultCode, null);
+ }
+
+ /**
+ * Get an intent that will invoke the next step of setup wizard.
+ *
+ * @param originalIntent The original intent that was used to start the step, usually via {@link
+ * android.app.Activity#getIntent()}.
+ * @param resultCode The result code of the step. See {@link ResultCodes}.
+ * @param data An intent containing extra result data.
+ * @return A new intent that can be used with {@link
+ * android.app.Activity#startActivityForResult(Intent, int)} to start the next step of the
+ * setup flow.
+ */
+ public static Intent getNextIntent(Intent originalIntent, int resultCode, Intent data) {
+ Intent intent = new Intent(ACTION_NEXT);
+ copyWizardManagerExtras(originalIntent, intent);
+ intent.putExtra(EXTRA_RESULT_CODE, resultCode);
+ if (data != null && data.getExtras() != null) {
+ intent.putExtras(data.getExtras());
}
-
- /**
- * Checks whether the current user has completed Setup Wizard. This is true if the current user
- * has gone through Setup Wizard. The current user may or may not be the device owner and the
- * device owner may have already completed setup wizard.
- *
- * @param context The context to retrieve the settings.
- * @return true if the current user has completed Setup Wizard.
- * @see #isDeviceProvisioned(android.content.Context)
- */
- public static boolean isUserSetupComplete(Context context) {
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
- return Settings.Secure.getInt(context.getContentResolver(),
- SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
- } else {
- // For versions below JB MR1, there are no user profiles. Just return the global device
- // provisioned state.
- return Settings.Secure.getInt(context.getContentResolver(),
- SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) == 1;
- }
- }
-
- /**
- * Checks whether the device is provisioned. This means that the device has gone through Setup
- * Wizard at least once. Note that the user can still be in Setup Wizard even if this is true,
- * for a secondary user profile triggered through Settings > Add account.
- *
- * @param context The context to retrieve the settings.
- * @return true if the device is provisioned.
- * @see #isUserSetupComplete(android.content.Context)
- */
- public static boolean isDeviceProvisioned(Context context) {
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
- return Settings.Global.getInt(context.getContentResolver(),
- SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) == 1;
- } else {
- return Settings.Secure.getInt(context.getContentResolver(),
- SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0) == 1;
- }
- }
-
- /**
- * Checks whether an intent is running in the deferred setup wizard flow.
- *
- * @param originalIntent The original intent that was used to start the step, usually via
- * {@link android.app.Activity#getIntent()}.
- * @return true if the intent passed in was running in deferred setup wizard.
- */
- public static boolean isDeferredSetupWizard(Intent originalIntent) {
- return originalIntent != null
- && originalIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false);
+ intent.putExtra(EXTRA_THEME, originalIntent.getStringExtra(EXTRA_THEME));
+
+ return intent;
+ }
+
+ /**
+ * Copy the internal extras used by setup wizard from one intent to another. For low-level use
+ * only, such as when using {@link Intent#FLAG_ACTIVITY_FORWARD_RESULT} to relay to another
+ * intent.
+ *
+ * @param srcIntent Intent to get the wizard manager extras from.
+ * @param dstIntent Intent to copy the wizard manager extras to.
+ */
+ public static void copyWizardManagerExtras(Intent srcIntent, Intent dstIntent) {
+ dstIntent.putExtra(EXTRA_WIZARD_BUNDLE, srcIntent.getBundleExtra(EXTRA_WIZARD_BUNDLE));
+ for (String key :
+ Arrays.asList(
+ EXTRA_IS_FIRST_RUN,
+ EXTRA_IS_DEFERRED_SETUP,
+ EXTRA_IS_PRE_DEFERRED_SETUP,
+ EXTRA_IS_SETUP_FLOW)) {
+ dstIntent.putExtra(key, srcIntent.getBooleanExtra(key, false));
}
- /**
- * Checks whether an intent is running in "pre-deferred" setup wizard flow.
- *
- * @param originalIntent The original intent that was used to start the step, usually via
- * {@link android.app.Activity#getIntent()}.
- * @return true if the intent passed in was running in "pre-deferred" setup wizard.
- */
- public static boolean isPreDeferredSetupWizard(Intent originalIntent) {
- return originalIntent != null
- && originalIntent.getBooleanExtra(EXTRA_IS_PRE_DEFERRED_SETUP, false);
+ for (String key : Arrays.asList(EXTRA_THEME, EXTRA_SCRIPT_URI, EXTRA_ACTION_ID)) {
+ dstIntent.putExtra(key, srcIntent.getStringExtra(key));
}
-
- /**
- * Checks the intent whether the extra indicates that the light theme should be used or not. If
- * the theme is not specified in the intent, or the theme specified is unknown, the value def
- * will be returned.
- *
- * @param intent The intent used to start the activity, which the theme extra will be read from.
- * @param def The default value if the theme is not specified.
- * @return True if the activity started by the given intent should use light theme.
- */
- public static boolean isLightTheme(Intent intent, boolean def) {
- final String theme = intent.getStringExtra(EXTRA_THEME);
- return isLightTheme(theme, def);
+ }
+
+ /**
+ * Check whether an intent is intended to be used within the setup wizard flow.
+ *
+ * @param intent The intent to be checked, usually from {@link android.app.Activity#getIntent()}.
+ * @return true if the intent passed in was intended to be used with setup wizard.
+ */
+ public static boolean isSetupWizardIntent(Intent intent) {
+ return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false);
+ }
+
+ /**
+ * Checks whether the current user has completed Setup Wizard. This is true if the current user
+ * has gone through Setup Wizard. The current user may or may not be the device owner and the
+ * device owner may have already completed setup wizard.
+ *
+ * @param context The context to retrieve the settings.
+ * @return true if the current user has completed Setup Wizard.
+ * @see #isDeviceProvisioned(android.content.Context)
+ */
+ public static boolean isUserSetupComplete(Context context) {
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ return Settings.Secure.getInt(
+ context.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0)
+ == 1;
+ } else {
+ // For versions below JB MR1, there are no user profiles. Just return the global device
+ // provisioned state.
+ return Settings.Secure.getInt(
+ context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0)
+ == 1;
}
-
- /**
- * Checks whether {@code theme} represents a light or dark theme. If the theme specified is
- * unknown, the value def will be returned.
- *
- * @param theme The theme as specified from an intent sent from setup wizard.
- * @param def The default value if the theme is not known.
- * @return True if {@code theme} represents a light theme.
- */
- public static boolean isLightTheme(String theme, boolean def) {
- if (THEME_HOLO_LIGHT.equals(theme) || THEME_MATERIAL_LIGHT.equals(theme)
- || THEME_GLIF_LIGHT.equals(theme) || THEME_GLIF_V2_LIGHT.equals(theme)
- || THEME_GLIF_V3_LIGHT.equals(theme)) {
- return true;
- } else if (THEME_HOLO.equals(theme) || THEME_MATERIAL.equals(theme)
- || THEME_GLIF.equals(theme) || THEME_GLIF_V2.equals(theme)
- || THEME_GLIF_V3.equals(theme)) {
- return false;
- } else {
- return def;
- }
+ }
+
+ /**
+ * Checks whether the device is provisioned. This means that the device has gone through Setup
+ * Wizard at least once. Note that the user can still be in Setup Wizard even if this is true, for
+ * a secondary user profile triggered through Settings > Add account.
+ *
+ * @param context The context to retrieve the settings.
+ * @return true if the device is provisioned.
+ * @see #isUserSetupComplete(android.content.Context)
+ */
+ public static boolean isDeviceProvisioned(Context context) {
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ return Settings.Global.getInt(
+ context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0)
+ == 1;
+ } else {
+ return Settings.Secure.getInt(
+ context.getContentResolver(), SETTINGS_GLOBAL_DEVICE_PROVISIONED, 0)
+ == 1;
}
-
- /**
- * Gets the theme style resource defined by this library for the theme specified in the given
- * intent. For example, for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned.
- *
- * @param intent The intent passed by setup wizard, or one with the theme propagated along using
- * {@link #copyWizardManagerExtras(Intent, Intent)}.
- * @return The style corresponding to the theme in the given intent, or {@code defaultTheme} if
- * the given theme is not recognized.
- *
- * @see #getThemeRes(String, int)
- */
- public static @StyleRes int getThemeRes(Intent intent, @StyleRes int defaultTheme) {
- final String theme = intent.getStringExtra(EXTRA_THEME);
- return getThemeRes(theme, defaultTheme);
- }
-
- /**
- * Gets the theme style resource defined by this library for the given theme name. For example,
- * for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned.
- *
- * <p>If you require extra theme attributes but want to ensure forward compatibility with new
- * themes added here, consider overriding {@link android.app.Activity#onApplyThemeResource} in
- * your activity and call {@link Theme#applyStyle(int, boolean)} using your theme overlay.
- *
- * <pre>{@code
- * protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
- * super.onApplyThemeResource(theme, resid, first);
- * theme.applyStyle(R.style.MyThemeOverlay, true);
- * }
- * }</pre>
- *
- * @param theme The string representation of the theme.
- * @return The style corresponding to the given {@code theme}, or {@code defaultTheme} if the
- * given theme is not recognized.
- */
- public static @StyleRes int getThemeRes(String theme, @StyleRes int defaultTheme) {
- if (theme != null) {
- switch (theme) {
- case THEME_GLIF_V3_LIGHT:
- return R.style.SuwThemeGlifV3_Light;
- case THEME_GLIF_V3:
- return R.style.SuwThemeGlifV3;
- case THEME_GLIF_V2_LIGHT:
- return R.style.SuwThemeGlifV2_Light;
- case THEME_GLIF_V2:
- return R.style.SuwThemeGlifV2;
- case THEME_GLIF_LIGHT:
- return R.style.SuwThemeGlif_Light;
- case THEME_GLIF:
- return R.style.SuwThemeGlif;
- case THEME_MATERIAL_LIGHT:
- return R.style.SuwThemeMaterial_Light;
- case THEME_MATERIAL:
- return R.style.SuwThemeMaterial;
- default:
- // fall through
- }
- }
- return defaultTheme;
+ }
+
+ /**
+ * Checks whether an intent is running in the deferred setup wizard flow.
+ *
+ * @param originalIntent The original intent that was used to start the step, usually via {@link
+ * android.app.Activity#getIntent()}.
+ * @return true if the intent passed in was running in deferred setup wizard.
+ */
+ public static boolean isDeferredSetupWizard(Intent originalIntent) {
+ return originalIntent != null && originalIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false);
+ }
+
+ /**
+ * Checks whether an intent is running in "pre-deferred" setup wizard flow.
+ *
+ * @param originalIntent The original intent that was used to start the step, usually via {@link
+ * android.app.Activity#getIntent()}.
+ * @return true if the intent passed in was running in "pre-deferred" setup wizard.
+ */
+ public static boolean isPreDeferredSetupWizard(Intent originalIntent) {
+ return originalIntent != null
+ && originalIntent.getBooleanExtra(EXTRA_IS_PRE_DEFERRED_SETUP, false);
+ }
+
+ /**
+ * Checks the intent whether the extra indicates that the light theme should be used or not. If
+ * the theme is not specified in the intent, or the theme specified is unknown, the value def will
+ * be returned. Note that day-night themes are not taken into account by this method.
+ *
+ * @param intent The intent used to start the activity, which the theme extra will be read from.
+ * @param def The default value if the theme is not specified.
+ * @return True if the activity started by the given intent should use light theme.
+ */
+ public static boolean isLightTheme(Intent intent, boolean def) {
+ final String theme = intent.getStringExtra(EXTRA_THEME);
+ return isLightTheme(theme, def);
+ }
+
+ /**
+ * Checks whether {@code theme} represents a light or dark theme. If the theme specified is
+ * unknown, the value def will be returned. Note that day-night themes are not taken into account
+ * by this method.
+ *
+ * @param theme The theme as specified from an intent sent from setup wizard.
+ * @param def The default value if the theme is not known.
+ * @return True if {@code theme} represents a light theme.
+ */
+ public static boolean isLightTheme(String theme, boolean def) {
+ if (THEME_HOLO_LIGHT.equals(theme)
+ || THEME_MATERIAL_LIGHT.equals(theme)
+ || THEME_GLIF_LIGHT.equals(theme)
+ || THEME_GLIF_V2_LIGHT.equals(theme)
+ || THEME_GLIF_V3_LIGHT.equals(theme)) {
+ return true;
+ } else if (THEME_HOLO.equals(theme)
+ || THEME_MATERIAL.equals(theme)
+ || THEME_GLIF.equals(theme)
+ || THEME_GLIF_V2.equals(theme)
+ || THEME_GLIF_V3.equals(theme)) {
+ return false;
+ } else {
+ return def;
}
+ }
+
+ /**
+ * Gets the theme style resource defined by this library for the theme specified in the given
+ * intent. For example, for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned.
+ *
+ * @param intent The intent passed by setup wizard, or one with the theme propagated along using
+ * {@link #copyWizardManagerExtras(Intent, Intent)}.
+ * @return The style corresponding to the theme in the given intent, or {@code defaultTheme} if
+ * the given theme is not recognized.
+ * @see #getThemeRes(String, int)
+ * @deprecated it is recommended to use {@link ThemeResolver} which allows setting the default
+ * theme in one place and applying it to multiple screens.
+ */
+ @Deprecated
+ public static @StyleRes int getThemeRes(Intent intent, @StyleRes int defaultTheme) {
+ return new ThemeResolver.Builder(ThemeResolver.getDefault())
+ .setDefaultTheme(defaultTheme)
+ .setUseDayNight(false)
+ .build()
+ .resolve(intent);
+ }
+
+ /**
+ * Gets the theme style resource defined by this library for the theme specified in the given
+ * intent. For example, for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned.
+ *
+ * @param intent The intent passed by setup wizard, or one with the theme propagated along using
+ * {@link #copyWizardManagerExtras(Intent, Intent)}.
+ * @return The style corresponding to the theme in the given intent, or {@code defaultTheme} if
+ * the given theme is not recognized. Return the {@code defaultTheme} if the specified theme
+ * is older than the oldest supported one.
+ * @see #getThemeRes(String, int)
+ * @deprecated it is recommended to use {@link ThemeResolver} which allows setting the default
+ * theme and oldest supported theme in one place and applying it to multiple screens.
+ */
+ @Deprecated
+ public static @StyleRes int getThemeRes(
+ Intent intent, @StyleRes int defaultTheme, @Nullable String oldestSupportedTheme) {
+ return new ThemeResolver.Builder(ThemeResolver.getDefault())
+ .setDefaultTheme(defaultTheme)
+ .setUseDayNight(false)
+ .setOldestSupportedTheme(oldestSupportedTheme)
+ .build()
+ .resolve(intent);
+ }
+
+ /**
+ * Gets the theme style resource defined by this library for the given theme name. For example,
+ * for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned.
+ *
+ * <p>If you require extra theme attributes but want to ensure forward compatibility with new
+ * themes added here, consider overriding {@link android.app.Activity#onApplyThemeResource} in
+ * your activity and call {@link Theme#applyStyle(int, boolean)} using your theme overlay.
+ *
+ * <pre>{@code
+ * protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
+ * super.onApplyThemeResource(theme, resid, first);
+ * theme.applyStyle(R.style.MyThemeOverlay, true);
+ * }
+ * }</pre>
+ *
+ * @param theme The string representation of the theme.
+ * @return The style corresponding to the given {@code theme}, or {@code defaultTheme} if the
+ * given theme is not recognized.
+ * @deprecated it is recommended to use {@link ThemeResolver} which allows setting the default
+ * theme in one place and applying it to multiple screens.
+ */
+ @Deprecated
+ public static @StyleRes int getThemeRes(
+ String theme, @StyleRes int defaultTheme, @Nullable String oldestSupportedTheme) {
+ return new ThemeResolver.Builder(ThemeResolver.getDefault())
+ .setDefaultTheme(defaultTheme)
+ .setUseDayNight(false)
+ .setOldestSupportedTheme(oldestSupportedTheme)
+ .build()
+ .resolve(theme);
+ }
+
+ /**
+ * Gets the theme style resource defined by this library for the given theme name. For example,
+ * for THEME_GLIF_LIGHT, the theme @style/SuwThemeGlif.Light is returned.
+ *
+ * <p>If you require extra theme attributes but want to ensure forward compatibility with new
+ * themes added here, consider overriding {@link android.app.Activity#onApplyThemeResource} in
+ * your activity and call {@link Theme#applyStyle(int, boolean)} using your theme overlay.
+ *
+ * <pre>{@code
+ * protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
+ * super.onApplyThemeResource(theme, resid, first);
+ * theme.applyStyle(R.style.MyThemeOverlay, true);
+ * }
+ * }</pre>
+ *
+ * @param theme The string representation of the theme.
+ * @return The style corresponding to the given {@code theme}, or {@code defaultTheme} if the
+ * given theme is not recognized.
+ * @deprecated it is recommended to use {@link ThemeResolver} which allows setting the default
+ * theme in one place and applying it to multiple screens.
+ */
+ @Deprecated
+ public static @StyleRes int getThemeRes(@Nullable String theme, @StyleRes int defaultTheme) {
+ return new ThemeResolver.Builder(ThemeResolver.getDefault())
+ .setDefaultTheme(defaultTheme)
+ .setUseDayNight(false)
+ .build()
+ .resolve(theme);
+ }
+
+ /**
+ * Reads the theme from the intent, and applies the theme to the activity as resolved by {@link
+ * ThemeResolver#getDefault()}.
+ *
+ * <p>If you require extra theme attributes, consider overriding {@link
+ * android.app.Activity#onApplyThemeResource} in your activity and call {@link
+ * Theme#applyStyle(int, boolean)} using your theme overlay.
+ *
+ * <pre>{@code
+ * protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
+ * super.onApplyThemeResource(theme, resid, first);
+ * theme.applyStyle(R.style.MyThemeOverlay, true);
+ * }
+ * }</pre>
+ *
+ * @param activity the activity to get the intent from and apply the resulting theme to.
+ */
+ public static void applyTheme(Activity activity) {
+ ThemeResolver.getDefault().applyTheme(activity);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/BottomScrollView.java b/library/main/src/com/android/setupwizardlib/view/BottomScrollView.java
index eeb40a9..962538f 100644
--- a/library/main/src/com/android/setupwizardlib/view/BottomScrollView.java
+++ b/library/main/src/com/android/setupwizardlib/view/BottomScrollView.java
@@ -17,12 +17,11 @@
package com.android.setupwizardlib.view;
import android.content.Context;
+import androidx.annotation.VisibleForTesting;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ScrollView;
-import androidx.annotation.VisibleForTesting;
-
/**
* An extension of ScrollView that will invoke a listener callback when the ScrollView needs
* scrolling, and when the ScrollView is being scrolled to the bottom. This is often used in Setup
@@ -30,75 +29,81 @@ import androidx.annotation.VisibleForTesting;
*/
public class BottomScrollView extends ScrollView {
- public interface BottomScrollListener {
- void onScrolledToBottom();
- void onRequiresScroll();
- }
+ public interface BottomScrollListener {
+ void onScrolledToBottom();
+
+ void onRequiresScroll();
+ }
- private BottomScrollListener mListener;
- private int mScrollThreshold;
- private boolean mRequiringScroll = false;
+ private BottomScrollListener listener;
+ private int scrollThreshold;
+ private boolean requiringScroll = false;
- private final Runnable mCheckScrollRunnable = new Runnable() {
+ private final Runnable checkScrollRunnable =
+ new Runnable() {
@Override
public void run() {
- checkScroll();
+ checkScroll();
}
- };
-
- public BottomScrollView(Context context) {
- super(context);
+ };
+
+ public BottomScrollView(Context context) {
+ super(context);
+ }
+
+ public BottomScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public BottomScrollView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setBottomScrollListener(BottomScrollListener l) {
+ listener = l;
+ }
+
+ @VisibleForTesting
+ public BottomScrollListener getBottomScrollListener() {
+ return listener;
+ }
+
+ @VisibleForTesting
+ public int getScrollThreshold() {
+ return scrollThreshold;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ final View child = getChildAt(0);
+ if (child != null) {
+ scrollThreshold = Math.max(0, child.getMeasuredHeight() - b + t - getPaddingBottom());
}
-
- public BottomScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ if (b - t > 0) {
+ // Post check scroll in the next run loop, so that the callback methods will be invoked
+ // after the layout pass. This way a new layout pass will be scheduled if view
+ // properties are changed in the callbacks.
+ post(checkScrollRunnable);
}
+ }
- public BottomScrollView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (oldt != t) {
+ checkScroll();
}
-
- public void setBottomScrollListener(BottomScrollListener l) {
- mListener = l;
+ }
+
+ private void checkScroll() {
+ if (listener != null) {
+ if (getScrollY() >= scrollThreshold) {
+ listener.onScrolledToBottom();
+ } else if (!requiringScroll) {
+ requiringScroll = true;
+ listener.onRequiresScroll();
+ }
}
-
- @VisibleForTesting
- public int getScrollThreshold() {
- return mScrollThreshold;
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- final View child = getChildAt(0);
- if (child != null) {
- mScrollThreshold = Math.max(0, child.getMeasuredHeight() - b + t - getPaddingBottom());
- }
- if (b - t > 0) {
- // Post check scroll in the next run loop, so that the callback methods will be invoked
- // after the layout pass. This way a new layout pass will be scheduled if view
- // properties are changed in the callbacks.
- post(mCheckScrollRunnable);
- }
- }
-
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt) {
- super.onScrollChanged(l, t, oldl, oldt);
- if (oldt != t) {
- checkScroll();
- }
- }
-
- private void checkScroll() {
- if (mListener != null) {
- if (getScrollY() >= mScrollThreshold) {
- mListener.onScrolledToBottom();
- } else if (!mRequiringScroll) {
- mRequiringScroll = true;
- mListener.onRequiresScroll();
- }
- }
- }
-
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/ButtonBarLayout.java b/library/main/src/com/android/setupwizardlib/view/ButtonBarLayout.java
index f7f5f99..4be4f56 100644
--- a/library/main/src/com/android/setupwizardlib/view/ButtonBarLayout.java
+++ b/library/main/src/com/android/setupwizardlib/view/ButtonBarLayout.java
@@ -20,105 +20,99 @@ import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
-
import com.android.setupwizardlib.R;
/**
* An extension of LinearLayout that automatically switches to vertical orientation when it can't
* fit its child views horizontally.
*
- * Modified from {@code com.android.internal.widget.ButtonBarLayout}
+ * <p>Modified from {@code com.android.internal.widget.ButtonBarLayout}
*/
public class ButtonBarLayout extends LinearLayout {
- private boolean mStacked = false;
- private int mOriginalPaddingLeft;
- private int mOriginalPaddingRight;
+ private boolean stacked = false;
+ private int originalPaddingLeft;
+ private int originalPaddingRight;
- public ButtonBarLayout(Context context) {
- super(context);
- }
+ public ButtonBarLayout(Context context) {
+ super(context);
+ }
- public ButtonBarLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
+ public ButtonBarLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- setStacked(false);
+ setStacked(false);
- boolean needsRemeasure = false;
+ boolean needsRemeasure = false;
- int initialWidthMeasureSpec = widthMeasureSpec;
- if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
- // Measure with WRAP_CONTENT, so that we can compare the measured size with the
- // available size to see if we need to stack.
- initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ int initialWidthMeasureSpec = widthMeasureSpec;
+ if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
+ // Measure with WRAP_CONTENT, so that we can compare the measured size with the
+ // available size to see if we need to stack.
+ initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- // We'll need to remeasure again to fill excess space.
- needsRemeasure = true;
- }
+ // We'll need to remeasure again to fill excess space.
+ needsRemeasure = true;
+ }
- super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
+ super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
- if (getMeasuredWidth() > widthSize) {
- setStacked(true);
+ if (getMeasuredWidth() > widthSize) {
+ setStacked(true);
- // Measure again in the new orientation.
- needsRemeasure = true;
- }
+ // Measure again in the new orientation.
+ needsRemeasure = true;
+ }
- if (needsRemeasure) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
+ if (needsRemeasure) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+ }
- private void setStacked(boolean stacked) {
- if (mStacked == stacked) {
- return;
- }
- mStacked = stacked;
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- LayoutParams childParams = (LayoutParams) child.getLayoutParams();
- if (stacked) {
- child.setTag(R.id.suw_original_weight, childParams.weight);
- childParams.weight = 0;
- } else {
- Float weight = (Float) child.getTag(R.id.suw_original_weight);
- if (weight != null) {
- childParams.weight = weight;
- }
- }
- child.setLayoutParams(childParams);
+ private void setStacked(boolean stacked) {
+ if (this.stacked == stacked) {
+ return;
+ }
+ this.stacked = stacked;
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ LayoutParams childParams = (LayoutParams) child.getLayoutParams();
+ if (stacked) {
+ child.setTag(R.id.suw_original_weight, childParams.weight);
+ childParams.weight = 0;
+ } else {
+ Float weight = (Float) child.getTag(R.id.suw_original_weight);
+ if (weight != null) {
+ childParams.weight = weight;
}
+ }
+ child.setLayoutParams(childParams);
+ }
- setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+ setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
- // Reverse the child order, so that the primary button is towards the top when vertical
- for (int i = childCount - 1; i >= 0; i--) {
- bringChildToFront(getChildAt(i));
- }
+ // Reverse the child order, so that the primary button is towards the top when vertical
+ for (int i = childCount - 1; i >= 0; i--) {
+ bringChildToFront(getChildAt(i));
+ }
- if (stacked) {
- // HACK: In the default button bar style, the left and right paddings are not
- // balanced to compensate for different alignment for borderless (left) button and
- // the raised (right) button. When it's stacked, we want the buttons to be centered,
- // so we balance out the paddings here.
- mOriginalPaddingLeft = getPaddingLeft();
- mOriginalPaddingRight = getPaddingRight();
- int paddingHorizontal = Math.max(mOriginalPaddingLeft, mOriginalPaddingRight);
- setPadding(
- paddingHorizontal, getPaddingTop(), paddingHorizontal, getPaddingBottom());
- } else {
- setPadding(
- mOriginalPaddingLeft,
- getPaddingTop(),
- mOriginalPaddingRight,
- getPaddingBottom());
- }
+ if (stacked) {
+ // HACK: In the default button bar style, the left and right paddings are not
+ // balanced to compensate for different alignment for borderless (left) button and
+ // the raised (right) button. When it's stacked, we want the buttons to be centered,
+ // so we balance out the paddings here.
+ originalPaddingLeft = getPaddingLeft();
+ originalPaddingRight = getPaddingRight();
+ int paddingHorizontal = Math.max(originalPaddingLeft, originalPaddingRight);
+ setPadding(paddingHorizontal, getPaddingTop(), paddingHorizontal, getPaddingBottom());
+ } else {
+ setPadding(originalPaddingLeft, getPaddingTop(), originalPaddingRight, getPaddingBottom());
}
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/CheckableLinearLayout.java b/library/main/src/com/android/setupwizardlib/view/CheckableLinearLayout.java
index 9605f99..fd2319c 100644
--- a/library/main/src/com/android/setupwizardlib/view/CheckableLinearLayout.java
+++ b/library/main/src/com/android/setupwizardlib/view/CheckableLinearLayout.java
@@ -19,74 +19,67 @@ package com.android.setupwizardlib.view;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build.VERSION_CODES;
+import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.LinearLayout;
-import androidx.annotation.Nullable;
-
/**
- * A LinearLayout which is checkable. This will set the checked state when
- * {@link #onCreateDrawableState(int)} is called, and can be used with
- * {@code android:duplicateParentState} to propagate the drawable state to child views.
+ * A LinearLayout which is checkable. This will set the checked state when {@link
+ * #onCreateDrawableState(int)} is called, and can be used with {@code android:duplicateParentState}
+ * to propagate the drawable state to child views.
*/
public class CheckableLinearLayout extends LinearLayout implements Checkable {
- private boolean mChecked = false;
+ private boolean checked = false;
- public CheckableLinearLayout(Context context) {
- super(context);
- }
+ public CheckableLinearLayout(Context context) {
+ super(context);
+ }
- public CheckableLinearLayout(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
+ public CheckableLinearLayout(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public CheckableLinearLayout(
- Context context,
- @Nullable AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public CheckableLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
- @TargetApi(VERSION_CODES.LOLLIPOP)
- public CheckableLinearLayout(
- Context context,
- AttributeSet attrs,
- int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
+ @TargetApi(VERSION_CODES.LOLLIPOP)
+ public CheckableLinearLayout(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
- {
- setFocusable(true);
- }
+ {
+ setFocusable(true);
+ }
- @Override
- protected int[] onCreateDrawableState(int extraSpace) {
- if (mChecked) {
- final int[] superStates = super.onCreateDrawableState(extraSpace + 1);
- final int[] checked = new int[] { android.R.attr.state_checked };
- return mergeDrawableStates(superStates, checked);
- } else {
- return super.onCreateDrawableState(extraSpace);
- }
+ @Override
+ protected int[] onCreateDrawableState(int extraSpace) {
+ if (this.checked) {
+ final int[] superStates = super.onCreateDrawableState(extraSpace + 1);
+ final int[] checked = new int[] {android.R.attr.state_checked};
+ return mergeDrawableStates(superStates, checked);
+ } else {
+ return super.onCreateDrawableState(extraSpace);
}
+ }
- @Override
- public void setChecked(boolean checked) {
- mChecked = checked;
- refreshDrawableState();
- }
+ @Override
+ public void setChecked(boolean checked) {
+ this.checked = checked;
+ refreshDrawableState();
+ }
- @Override
- public boolean isChecked() {
- return mChecked;
- }
+ @Override
+ public boolean isChecked() {
+ return checked;
+ }
- @Override
- public void toggle() {
- setChecked(!isChecked());
- }
+ @Override
+ public void toggle() {
+ setChecked(!isChecked());
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/FillContentLayout.java b/library/main/src/com/android/setupwizardlib/view/FillContentLayout.java
index 2c28090..b72d4d2 100644
--- a/library/main/src/com/android/setupwizardlib/view/FillContentLayout.java
+++ b/library/main/src/com/android/setupwizardlib/view/FillContentLayout.java
@@ -21,13 +21,12 @@ import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
-
import com.android.setupwizardlib.R;
/**
- * A layout that will measure its children size based on the space it is given, by using its
- * {@code android:minWidth}, {@code android:minHeight}, {@code android:maxWidth}, and
- * {@code android:maxHeight} values.
+ * A layout that will measure its children size based on the space it is given, by using its {@code
+ * android:minWidth}, {@code android:minHeight}, {@code android:maxWidth}, and {@code
+ * android:maxHeight} values.
*
* <p>Typically this is used to show an illustration image or video on the screen. For optimal UX,
* those assets typically want to occupy the remaining space available on screen within a certain
@@ -42,84 +41,82 @@ import com.android.setupwizardlib.R;
*/
public class FillContentLayout extends FrameLayout {
- private int mMaxWidth;
- private int mMaxHeight;
-
- public FillContentLayout(Context context) {
- this(context, null);
- }
-
- public FillContentLayout(Context context, AttributeSet attrs) {
- this(context, attrs, R.attr.suwFillContentLayoutStyle);
- }
-
- public FillContentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs, defStyleAttr);
- }
+ private int maxWidth;
+ private int maxHeight;
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- TypedArray a = context.obtainStyledAttributes(
- attrs,
- R.styleable.SuwFillContentLayout,
- defStyleAttr,
- 0);
+ public FillContentLayout(Context context) {
+ this(context, null);
+ }
- mMaxHeight = a.getDimensionPixelSize(
- R.styleable.SuwFillContentLayout_android_maxHeight, -1);
- mMaxWidth = a.getDimensionPixelSize(R.styleable.SuwFillContentLayout_android_maxWidth, -1);
+ public FillContentLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.suwFillContentLayoutStyle);
+ }
- a.recycle();
- }
+ public FillContentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs, defStyleAttr);
+ }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // Measure this view with the minWidth and minHeight, without asking the children.
- // (Children size is the drawable's intrinsic size, and we don't want that to influence
- // the size of the illustration).
- setMeasuredDimension(
- getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
- getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
-
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- measureIllustrationChild(getChildAt(i), getMeasuredWidth(), getMeasuredHeight());
- }
- }
+ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
+ TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.SuwFillContentLayout, defStyleAttr, 0);
- private void measureIllustrationChild(View child, int parentWidth, int parentHeight) {
- // Modified from ViewGroup#measureChildWithMargins
- final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+ maxHeight = a.getDimensionPixelSize(R.styleable.SuwFillContentLayout_android_maxHeight, -1);
+ maxWidth = a.getDimensionPixelSize(R.styleable.SuwFillContentLayout_android_maxWidth, -1);
- // Create measure specs that are no bigger than min(parentSize, maxSize)
+ a.recycle();
+ }
- int childWidthMeasureSpec = getMaxSizeMeasureSpec(
- Math.min(mMaxWidth, parentWidth),
- getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin,
- lp.width);
- int childHeightMeasureSpec = getMaxSizeMeasureSpec(
- Math.min(mMaxHeight, parentHeight),
- getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin,
- lp.height);
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Measure this view with the minWidth and minHeight, without asking the children.
+ // (Children size is the drawable's intrinsic size, and we don't want that to influence
+ // the size of the illustration).
+ setMeasuredDimension(
+ getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
+ getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ measureIllustrationChild(getChildAt(i), getMeasuredWidth(), getMeasuredHeight());
}
-
- private static int getMaxSizeMeasureSpec(int maxSize, int padding, int childDimension) {
- // Modified from ViewGroup#getChildMeasureSpec
- int size = Math.max(0, maxSize - padding);
-
- if (childDimension >= 0) {
- // Child wants a specific size... so be it
- return MeasureSpec.makeMeasureSpec(childDimension, MeasureSpec.EXACTLY);
- } else if (childDimension == LayoutParams.MATCH_PARENT) {
- // Child wants to be our size. So be it.
- return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
- } else if (childDimension == LayoutParams.WRAP_CONTENT) {
- // Child wants to determine its own size. It can't be
- // bigger than us.
- return MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
- }
- return 0;
+ }
+
+ private void measureIllustrationChild(View child, int parentWidth, int parentHeight) {
+ // Modified from ViewGroup#measureChildWithMargins
+ final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+ // Create measure specs that are no bigger than min(parentSize, maxSize)
+
+ int childWidthMeasureSpec =
+ getMaxSizeMeasureSpec(
+ Math.min(maxWidth, parentWidth),
+ getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin,
+ lp.width);
+ int childHeightMeasureSpec =
+ getMaxSizeMeasureSpec(
+ Math.min(maxHeight, parentHeight),
+ getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin,
+ lp.height);
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+
+ private static int getMaxSizeMeasureSpec(int maxSize, int padding, int childDimension) {
+ // Modified from ViewGroup#getChildMeasureSpec
+ int size = Math.max(0, maxSize - padding);
+
+ if (childDimension >= 0) {
+ // Child wants a specific size... so be it
+ return MeasureSpec.makeMeasureSpec(childDimension, MeasureSpec.EXACTLY);
+ } else if (childDimension == LayoutParams.MATCH_PARENT) {
+ // Child wants to be our size. So be it.
+ return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+ } else if (childDimension == LayoutParams.WRAP_CONTENT) {
+ // Child wants to determine its own size. It can't be
+ // bigger than us.
+ return MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
}
+ return 0;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/Illustration.java b/library/main/src/com/android/setupwizardlib/view/Illustration.java
index c6968f8..e9cd4b5 100644
--- a/library/main/src/com/android/setupwizardlib/view/Illustration.java
+++ b/library/main/src/com/android/setupwizardlib/view/Illustration.java
@@ -30,7 +30,6 @@ import android.util.LayoutDirection;
import android.view.Gravity;
import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
-
import com.android.setupwizardlib.R;
/**
@@ -39,184 +38,190 @@ import com.android.setupwizardlib.R;
* drawable to fit the width of the view and fills the rest with the background.
*
* <p>If an aspect ratio is set, then the aspect ratio of the source drawable is maintained.
- * Otherwise the the aspect ratio will be ignored, only increasing the width of the illustration.
+ * Otherwise the aspect ratio will be ignored, only increasing the width of the illustration.
*/
public class Illustration extends FrameLayout {
- // Size of the baseline grid in pixels
- private float mBaselineGridSize;
- private Drawable mBackground;
- private Drawable mIllustration;
- private final Rect mViewBounds = new Rect();
- private final Rect mIllustrationBounds = new Rect();
- private float mScale = 1.0f;
- private float mAspectRatio = 0.0f;
-
- public Illustration(Context context) {
- super(context);
- init(null, 0);
- }
-
- public Illustration(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs, 0);
+ // Size of the baseline grid in pixels
+ private float baselineGridSize;
+ private Drawable background;
+ private Drawable illustration;
+ private final Rect viewBounds = new Rect();
+ private final Rect illustrationBounds = new Rect();
+ private float scale = 1.0f;
+ private float aspectRatio = 0.0f;
+
+ public Illustration(Context context) {
+ super(context);
+ init(null, 0);
+ }
+
+ public Illustration(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public Illustration(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ // All the constructors delegate to this init method. The 3-argument constructor is not
+ // available in FrameLayout before v11, so call super with the exact same arguments.
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ if (attrs != null) {
+ TypedArray a =
+ getContext().obtainStyledAttributes(attrs, R.styleable.SuwIllustration, defStyleAttr, 0);
+ aspectRatio = a.getFloat(R.styleable.SuwIllustration_suwAspectRatio, 0.0f);
+ a.recycle();
}
-
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public Illustration(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(attrs, defStyleAttr);
+ // Number of pixels of the 8dp baseline grid as defined in material design specs
+ baselineGridSize = getResources().getDisplayMetrics().density * 8;
+ setWillNotDraw(false);
+ }
+
+ /**
+ * The background will be drawn to fill up the rest of the view. It will also be scaled by the
+ * same amount as the foreground so their textures look the same.
+ */
+ // Override the deprecated setBackgroundDrawable method to support API < 16. View.setBackground
+ // forwards to setBackgroundDrawable in the framework implementation.
+ @SuppressWarnings("deprecation")
+ @Override
+ public void setBackgroundDrawable(Drawable background) {
+ if (background == this.background) {
+ return;
}
-
- // All the constructors delegate to this init method. The 3-argument constructor is not
- // available in FrameLayout before v11, so call super with the exact same arguments.
- private void init(AttributeSet attrs, int defStyleAttr) {
- if (attrs != null) {
- TypedArray a = getContext().obtainStyledAttributes(attrs,
- R.styleable.SuwIllustration, defStyleAttr, 0);
- mAspectRatio = a.getFloat(R.styleable.SuwIllustration_suwAspectRatio, 0.0f);
- a.recycle();
- }
- // Number of pixels of the 8dp baseline grid as defined in material design specs
- mBaselineGridSize = getResources().getDisplayMetrics().density * 8;
- setWillNotDraw(false);
- }
-
- /**
- * The background will be drawn to fill up the rest of the view. It will also be scaled by the
- * same amount as the foreground so their textures look the same.
- */
- // Override the deprecated setBackgroundDrawable method to support API < 16. View.setBackground
- // forwards to setBackgroundDrawable in the framework implementation.
- @SuppressWarnings("deprecation")
- @Override
- public void setBackgroundDrawable(Drawable background) {
- if (background == mBackground) {
- return;
- }
- mBackground = background;
- invalidate();
- requestLayout();
+ this.background = background;
+ invalidate();
+ requestLayout();
+ }
+
+ /**
+ * Sets the drawable used as the illustration. The drawable is expected to have intrinsic width
+ * and height defined and will be scaled to fit the width of the view.
+ */
+ public void setIllustration(Drawable illustration) {
+ if (illustration == this.illustration) {
+ return;
}
-
- /**
- * Sets the drawable used as the illustration. The drawable is expected to have intrinsic
- * width and height defined and will be scaled to fit the width of the view.
- */
- public void setIllustration(Drawable illustration) {
- if (illustration == mIllustration) {
- return;
- }
- mIllustration = illustration;
- invalidate();
- requestLayout();
+ this.illustration = illustration;
+ invalidate();
+ requestLayout();
+ }
+
+ /**
+ * Set the aspect ratio reserved for the illustration. This overrides the top padding of the view
+ * according to the width of this view and the aspect ratio. Children views will start being laid
+ * out below this aspect ratio.
+ *
+ * @param aspectRatio A float value specifying the aspect ratio (= width / height). 0 to not
+ * override the top padding.
+ */
+ public void setAspectRatio(float aspectRatio) {
+ this.aspectRatio = aspectRatio;
+ invalidate();
+ requestLayout();
+ }
+
+ @Override
+ @Deprecated
+ public void setForeground(Drawable d) {
+ setIllustration(d);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (aspectRatio != 0.0f) {
+ int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
+ int illustrationHeight = (int) (parentWidth / aspectRatio);
+ illustrationHeight = (int) (illustrationHeight - (illustrationHeight % baselineGridSize));
+ setPadding(0, illustrationHeight, 0, 0);
}
-
- /**
- * Set the aspect ratio reserved for the illustration. This overrides the top padding of the
- * view according to the width of this view and the aspect ratio. Children views will start
- * being laid out below this aspect ratio.
- *
- * @param aspectRatio A float value specifying the aspect ratio (= width / height). 0 to not
- * override the top padding.
- */
- public void setAspectRatio(float aspectRatio) {
- mAspectRatio = aspectRatio;
- invalidate();
- requestLayout();
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ //noinspection AndroidLintInlinedApi
+ setOutlineProvider(ViewOutlineProvider.BOUNDS);
}
-
- @Override
- @Deprecated
- public void setForeground(Drawable d) {
- setIllustration(d);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final int layoutWidth = right - left;
+ final int layoutHeight = bottom - top;
+ if (illustration != null) {
+ int intrinsicWidth = illustration.getIntrinsicWidth();
+ int intrinsicHeight = illustration.getIntrinsicHeight();
+
+ viewBounds.set(0, 0, layoutWidth, layoutHeight);
+ if (aspectRatio != 0f) {
+ scale = layoutWidth / (float) intrinsicWidth;
+ intrinsicWidth = layoutWidth;
+ intrinsicHeight = (int) (intrinsicHeight * scale);
+ }
+ Gravity.apply(
+ Gravity.FILL_HORIZONTAL | Gravity.TOP,
+ intrinsicWidth,
+ intrinsicHeight,
+ viewBounds,
+ illustrationBounds);
+ illustration.setBounds(illustrationBounds);
}
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mAspectRatio != 0.0f) {
- int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
- int illustrationHeight = (int) (parentWidth / mAspectRatio);
- illustrationHeight =
- (int) (illustrationHeight - (illustrationHeight % mBaselineGridSize));
- setPadding(0, illustrationHeight, 0, 0);
- }
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- //noinspection AndroidLintInlinedApi
- setOutlineProvider(ViewOutlineProvider.BOUNDS);
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (background != null) {
+ // Scale the background bounds by the same scale to compensate for the scale done to the
+ // canvas in onDraw.
+ background.setBounds(
+ 0,
+ 0,
+ (int) Math.ceil(layoutWidth / scale),
+ (int) Math.ceil((layoutHeight - illustrationBounds.height()) / scale));
}
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- final int layoutWidth = right - left;
- final int layoutHeight = bottom - top;
- if (mIllustration != null) {
- int intrinsicWidth = mIllustration.getIntrinsicWidth();
- int intrinsicHeight = mIllustration.getIntrinsicHeight();
-
- mViewBounds.set(0, 0, layoutWidth, layoutHeight);
- if (mAspectRatio != 0f) {
- mScale = layoutWidth / (float) intrinsicWidth;
- intrinsicWidth = layoutWidth;
- intrinsicHeight = (int) (intrinsicHeight * mScale);
- }
- Gravity.apply(Gravity.FILL_HORIZONTAL | Gravity.TOP, intrinsicWidth,
- intrinsicHeight, mViewBounds, mIllustrationBounds);
- mIllustration.setBounds(mIllustrationBounds);
- }
- if (mBackground != null) {
- // Scale the background bounds by the same scale to compensate for the scale done to the
- // canvas in onDraw.
- mBackground.setBounds(0, 0, (int) Math.ceil(layoutWidth / mScale),
- (int) Math.ceil((layoutHeight - mIllustrationBounds.height()) / mScale));
- }
- super.onLayout(changed, left, top, right, bottom);
+ super.onLayout(changed, left, top, right, bottom);
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (background != null) {
+ // Draw the background filling parts not covered by the illustration
+ canvas.save();
+ canvas.translate(0, illustrationBounds.height());
+ // Scale the background so its size matches the foreground
+ canvas.scale(scale, scale, 0, 0);
+ if (VERSION.SDK_INT > VERSION_CODES.JELLY_BEAN_MR1
+ && shouldMirrorDrawable(background, getLayoutDirection())) {
+ // Flip the illustration for RTL layouts
+ canvas.scale(-1, 1);
+ canvas.translate(-background.getBounds().width(), 0);
+ }
+ background.draw(canvas);
+ canvas.restore();
}
-
- @Override
- public void onDraw(Canvas canvas) {
- if (mBackground != null) {
- // Draw the background filling parts not covered by the illustration
- canvas.save();
- canvas.translate(0, mIllustrationBounds.height());
- // Scale the background so its size matches the foreground
- canvas.scale(mScale, mScale, 0, 0);
- if (VERSION.SDK_INT > VERSION_CODES.JELLY_BEAN_MR1 &&
- shouldMirrorDrawable(mBackground, getLayoutDirection())) {
- // Flip the illustration for RTL layouts
- canvas.scale(-1, 1);
- canvas.translate(-mBackground.getBounds().width(), 0);
- }
- mBackground.draw(canvas);
- canvas.restore();
- }
- if (mIllustration != null) {
- canvas.save();
- if (VERSION.SDK_INT > VERSION_CODES.JELLY_BEAN_MR1 &&
- shouldMirrorDrawable(mIllustration, getLayoutDirection())) {
- // Flip the illustration for RTL layouts
- canvas.scale(-1, 1);
- canvas.translate(-mIllustrationBounds.width(), 0);
- }
- // Draw the illustration
- mIllustration.draw(canvas);
- canvas.restore();
- }
- super.onDraw(canvas);
+ if (illustration != null) {
+ canvas.save();
+ if (VERSION.SDK_INT > VERSION_CODES.JELLY_BEAN_MR1
+ && shouldMirrorDrawable(illustration, getLayoutDirection())) {
+ // Flip the illustration for RTL layouts
+ canvas.scale(-1, 1);
+ canvas.translate(-illustrationBounds.width(), 0);
+ }
+ // Draw the illustration
+ illustration.draw(canvas);
+ canvas.restore();
}
-
- private boolean shouldMirrorDrawable(Drawable drawable, int layoutDirection) {
- if (layoutDirection == LayoutDirection.RTL) {
- if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- return drawable.isAutoMirrored();
- } else if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
- final int flags = getContext().getApplicationInfo().flags;
- //noinspection AndroidLintInlinedApi
- return (flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0;
- }
- }
- return false;
+ super.onDraw(canvas);
+ }
+
+ private boolean shouldMirrorDrawable(Drawable drawable, int layoutDirection) {
+ if (layoutDirection == LayoutDirection.RTL) {
+ if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ return drawable.isAutoMirrored();
+ } else if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ final int flags = getContext().getApplicationInfo().flags;
+ //noinspection AndroidLintInlinedApi
+ return (flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0;
+ }
}
+ return false;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java b/library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java
index 53149ea..375ee18 100644
--- a/library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java
+++ b/library/main/src/com/android/setupwizardlib/view/IllustrationVideoView.java
@@ -22,18 +22,23 @@ import android.content.res.TypedArray;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.Animatable;
import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.MediaPlayer.OnInfoListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.media.MediaPlayer.OnSeekCompleteListener;
+import android.net.Uri;
import android.os.Build.VERSION_CODES;
+import androidx.annotation.Nullable;
+import androidx.annotation.RawRes;
+import androidx.annotation.VisibleForTesting;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
import android.view.View;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.RawRes;
-import androidx.annotation.VisibleForTesting;
-
import com.android.setupwizardlib.R;
+import java.io.IOException;
/**
* A view for displaying videos in a continuous loop (without audio). This is typically used for
@@ -44,255 +49,295 @@ import com.android.setupwizardlib.R;
* should loop back to
*
* <p>For optimal file size, use avconv or other video compression tool to remove the unused audio
- * track and reduce the size of your video asset:
- * avconv -i [input file] -vcodec h264 -crf 20 -an [output_file]
+ * track and reduce the size of your video asset: avconv -i [input file] -vcodec h264 -crf 20 -an
+ * [output_file]
*/
@TargetApi(VERSION_CODES.ICE_CREAM_SANDWICH)
-public class IllustrationVideoView extends TextureView implements Animatable,
- TextureView.SurfaceTextureListener,
- MediaPlayer.OnPreparedListener,
- MediaPlayer.OnSeekCompleteListener,
- MediaPlayer.OnInfoListener {
+public class IllustrationVideoView extends TextureView
+ implements Animatable,
+ SurfaceTextureListener,
+ OnPreparedListener,
+ OnSeekCompleteListener,
+ OnInfoListener,
+ OnErrorListener {
- private static final String TAG = "IllustrationVideoView";
+ private static final String TAG = "IllustrationVideoView";
- protected float mAspectRatio = 1.0f; // initial guess until we know
+ protected float mAspectRatio = 1.0f; // initial guess until we know
- @Nullable // Can be null when media player fails to initialize
- protected MediaPlayer mMediaPlayer;
+ @Nullable // Can be null when media player fails to initialize
+ protected MediaPlayer mMediaPlayer;
- private @RawRes int mVideoResId = 0;
+ private @RawRes int videoResId = 0;
- @VisibleForTesting Surface mSurface;
+ private String videoResPackageName;
- protected int mWindowVisibility;
+ @VisibleForTesting Surface surface;
- public IllustrationVideoView(Context context, AttributeSet attrs) {
- super(context, attrs);
- final TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.SuwIllustrationVideoView);
- mVideoResId = a.getResourceId(R.styleable.SuwIllustrationVideoView_suwVideo, 0);
- a.recycle();
+ private boolean prepared;
- // By default the video scales without interpolation, resulting in jagged edges in the
- // video. This works around it by making the view go through scaling, which will apply
- // anti-aliasing effects.
- setScaleX(0.9999999f);
- setScaleX(0.9999999f);
+ public IllustrationVideoView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.SuwIllustrationVideoView);
+ final int videoResId = a.getResourceId(R.styleable.SuwIllustrationVideoView_suwVideo, 0);
+ a.recycle();
+ setVideoResource(videoResId);
- setSurfaceTextureListener(this);
- }
+ // By default the video scales without interpolation, resulting in jagged edges in the
+ // video. This works around it by making the view go through scaling, which will apply
+ // anti-aliasing effects.
+ setScaleX(0.9999999f);
+ setScaleX(0.9999999f);
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
-
- if (height < width * mAspectRatio) {
- // Height constraint is tighter. Need to scale down the width to fit aspect ratio.
- width = (int) (height / mAspectRatio);
- } else {
- // Width constraint is tighter. Need to scale down the height to fit aspect ratio.
- height = (int) (width * mAspectRatio);
- }
-
- super.onMeasure(
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
- }
+ setSurfaceTextureListener(this);
+ }
- /**
- * Set the video to be played by this view.
- *
- * @param resId Resource ID of the video, typically an MP4 under res/raw.
- */
- public void setVideoResource(@RawRes int resId) {
- if (resId != mVideoResId) {
- mVideoResId = resId;
- createMediaPlayer();
- }
- }
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- super.onWindowFocusChanged(hasWindowFocus);
- if (hasWindowFocus) {
- start();
- } else {
- stop();
- }
+ if (height < width * mAspectRatio) {
+ // Height constraint is tighter. Need to scale down the width to fit aspect ratio.
+ width = (int) (height / mAspectRatio);
+ } else {
+ // Width constraint is tighter. Need to scale down the height to fit aspect ratio.
+ height = (int) (width * mAspectRatio);
}
- /**
- * Creates a media player for the current URI. The media player will be started immediately if
- * the view's window is visible. If there is an existing media player, it will be released.
- */
- protected void createMediaPlayer() {
- if (mMediaPlayer != null) {
- mMediaPlayer.release();
- }
- if (mSurface == null || mVideoResId == 0) {
- return;
- }
-
- mMediaPlayer = MediaPlayer.create(getContext(), mVideoResId);
-
- if (mMediaPlayer != null) {
- mMediaPlayer.setSurface(mSurface);
- mMediaPlayer.setOnPreparedListener(this);
- mMediaPlayer.setOnSeekCompleteListener(this);
- mMediaPlayer.setOnInfoListener(this);
-
- float aspectRatio =
- (float) mMediaPlayer.getVideoHeight() / mMediaPlayer.getVideoWidth();
- if (mAspectRatio != aspectRatio) {
- mAspectRatio = aspectRatio;
- requestLayout();
- }
- } else {
- Log.wtf(TAG, "Unable to initialize media player for video view");
- }
- if (mWindowVisibility == View.VISIBLE) {
- start();
- }
+ super.onMeasure(
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
+
+ /**
+ * Set the video and video package name to be played by this view.
+ *
+ * @param videoResId Resource ID of the video, typically an MP4 under res/raw.
+ * @param videoResPackageName The package name of videoResId.
+ */
+ public void setVideoResource(@RawRes int videoResId, String videoResPackageName) {
+ if (videoResId != this.videoResId
+ || (videoResPackageName != null && !videoResPackageName.equals(this.videoResPackageName))) {
+ this.videoResId = videoResId;
+ this.videoResPackageName = videoResPackageName;
+ createMediaPlayer();
}
-
- protected void createSurface() {
- if (mSurface != null) {
- mSurface.release();
- mSurface = null;
- }
- // Reattach only if it has been previously released
- SurfaceTexture surfaceTexture = getSurfaceTexture();
- if (surfaceTexture != null) {
- setVisibility(View.INVISIBLE);
- mSurface = new Surface(surfaceTexture);
- }
+ }
+
+ /**
+ * Set the video to be played by this view.
+ *
+ * @param resId Resource ID of the video, typically an MP4 under res/raw.
+ */
+ public void setVideoResource(@RawRes int resId) {
+ setVideoResource(resId, getContext().getPackageName());
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ super.onWindowFocusChanged(hasWindowFocus);
+ if (hasWindowFocus) {
+ start();
+ } else {
+ stop();
}
-
- @Override
- protected void onWindowVisibilityChanged(int visibility) {
- super.onWindowVisibilityChanged(visibility);
- mWindowVisibility = visibility;
- if (visibility == View.VISIBLE) {
- reattach();
- } else {
- release();
- }
+ }
+
+ /**
+ * Creates a media player for the current URI. The media player will be started immediately if the
+ * view's window is visible. If there is an existing media player, it will be released.
+ */
+ protected void createMediaPlayer() {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.release();
}
-
- /**
- * Whether the media player should play the video in a continuous loop. The default value is
- * true.
- */
- protected boolean shouldLoop() {
- return true;
+ if (surface == null || videoResId == 0) {
+ return;
}
- /**
- * Release any resources used by this view. This is automatically called in
- * onSurfaceTextureDestroyed so in most cases you don't have to call this.
- */
- public void release() {
- if (mMediaPlayer != null) {
- mMediaPlayer.stop();
- mMediaPlayer.release();
- mMediaPlayer = null;
- }
- if (mSurface != null) {
- mSurface.release();
- mSurface = null;
- }
+ mMediaPlayer = new MediaPlayer();
+
+ mMediaPlayer.setSurface(surface);
+ mMediaPlayer.setOnPreparedListener(this);
+ mMediaPlayer.setOnSeekCompleteListener(this);
+ mMediaPlayer.setOnInfoListener(this);
+ mMediaPlayer.setOnErrorListener(this);
+
+ setVideoResourceInternal(videoResId, videoResPackageName);
+ }
+
+ private void setVideoResourceInternal(@RawRes int videoRes, String videoResPackageName) {
+ Uri uri = Uri.parse("android.resource://" + videoResPackageName + "/" + videoRes);
+ try {
+ mMediaPlayer.setDataSource(getContext(), uri, null);
+ mMediaPlayer.prepareAsync();
+ } catch (IOException e) {
+ Log.wtf(TAG, "Unable to set data source", e);
}
+ }
- private void reattach() {
- if (mSurface == null) {
- initVideo();
- }
+ protected void createSurface() {
+ if (surface != null) {
+ surface.release();
+ surface = null;
+ }
+ // Reattach only if it has been previously released
+ SurfaceTexture surfaceTexture = getSurfaceTexture();
+ if (surfaceTexture != null) {
+ setVisibility(View.INVISIBLE);
+ surface = new Surface(surfaceTexture);
}
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility == View.VISIBLE) {
+ reattach();
+ } else {
+ release();
+ }
+ }
+
+ /**
+ * Whether the media player should play the video in a continuous loop. The default value is true.
+ */
+ protected boolean shouldLoop() {
+ return true;
+ }
+
+ /**
+ * Release any resources used by this view. This is automatically called in
+ * onSurfaceTextureDestroyed so in most cases you don't have to call this.
+ */
+ public void release() {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.release();
+ mMediaPlayer = null;
+ prepared = false;
+ }
+ if (surface != null) {
+ surface.release();
+ surface = null;
+ }
+ }
- private void initVideo() {
- if (mWindowVisibility != View.VISIBLE) {
- return;
- }
- createSurface();
- if (mSurface != null) {
- createMediaPlayer();
- } else {
- Log.w("IllustrationVideoView", "Surface creation failed");
- }
+ private void reattach() {
+ if (surface == null) {
+ initVideo();
}
+ }
- protected void onRenderingStart() {
+ private void initVideo() {
+ if (getWindowVisibility() != View.VISIBLE) {
+ return;
}
+ createSurface();
+ if (surface != null) {
+ createMediaPlayer();
+ } else {
+ Log.w(TAG, "Surface creation failed");
+ }
+ }
- /* SurfaceTextureListener methods */
+ protected void onRenderingStart() {}
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
- // Keep the view hidden until video starts
- setVisibility(View.INVISIBLE);
- initVideo();
- }
+ /* SurfaceTextureListener methods */
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
- }
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
+ // Keep the view hidden until video starts
+ setVisibility(View.INVISIBLE);
+ initVideo();
+ }
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
- release();
- return true;
- }
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {}
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
- }
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+ release();
+ return true;
+ }
- /* Animatable methods */
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}
- @Override
- public void start() {
- if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
- mMediaPlayer.start();
- }
- }
+ /* Animatable methods */
- @Override
- public void stop() {
- if (mMediaPlayer != null) {
- mMediaPlayer.pause();
- }
+ @Override
+ public void start() {
+ if (prepared && mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
+ mMediaPlayer.start();
}
+ }
- @Override
- public boolean isRunning() {
- return mMediaPlayer != null && mMediaPlayer.isPlaying();
+ @Override
+ public void stop() {
+ if (prepared && mMediaPlayer != null) {
+ mMediaPlayer.pause();
}
+ }
- /* MediaPlayer callbacks */
+ @Override
+ public boolean isRunning() {
+ return mMediaPlayer != null && mMediaPlayer.isPlaying();
+ }
- @Override
- public boolean onInfo(MediaPlayer mp, int what, int extra) {
- if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
- // Video available, show view now
- setVisibility(View.VISIBLE);
- onRenderingStart();
- }
- return false;
- }
+ /* MediaPlayer callbacks */
- @Override
- public void onPrepared(MediaPlayer mp) {
- mp.setLooping(shouldLoop());
+ @Override
+ public boolean onInfo(MediaPlayer mp, int what, int extra) {
+ if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
+ // Video available, show view now
+ setVisibility(View.VISIBLE);
+ onRenderingStart();
}
-
- @Override
- public void onSeekComplete(MediaPlayer mp) {
- mp.start();
+ return false;
+ }
+
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ prepared = true;
+ mp.setLooping(shouldLoop());
+
+ float aspectRatio = 0.0f;
+ if (mp.getVideoWidth() > 0 && mp.getVideoHeight() > 0) {
+ aspectRatio = (float) mp.getVideoHeight() / mp.getVideoWidth();
+ } else {
+ Log.w(TAG, "Unexpected video size=" + mp.getVideoWidth() + "x" + mp.getVideoHeight());
}
-
- public int getCurrentPosition() {
- return mMediaPlayer == null ? 0 : mMediaPlayer.getCurrentPosition();
+ if (Float.compare(mAspectRatio, aspectRatio) != 0) {
+ mAspectRatio = aspectRatio;
+ requestLayout();
+ }
+ if (getWindowVisibility() == View.VISIBLE) {
+ start();
}
+ }
+
+ @Override
+ public void onSeekComplete(MediaPlayer mp) {
+ if (isPrepared()) {
+ mp.start();
+ } else {
+ Log.wtf(TAG, "Seek complete but media player not prepared");
+ }
+ }
+
+ public int getCurrentPosition() {
+ return mMediaPlayer == null ? 0 : mMediaPlayer.getCurrentPosition();
+ }
+
+ protected boolean isPrepared() {
+ return prepared;
+ }
+
+ @Override
+ public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
+ Log.w(TAG, "MediaPlayer error. what=" + what + " extra=" + extra);
+ return false;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/IntrinsicSizeFrameLayout.java b/library/main/src/com/android/setupwizardlib/view/IntrinsicSizeFrameLayout.java
index 02fdcc7..c6a38f6 100644
--- a/library/main/src/com/android/setupwizardlib/view/IntrinsicSizeFrameLayout.java
+++ b/library/main/src/com/android/setupwizardlib/view/IntrinsicSizeFrameLayout.java
@@ -22,71 +22,71 @@ import android.content.res.TypedArray;
import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.widget.FrameLayout;
-
import com.android.setupwizardlib.R;
/**
* A FrameLayout subclass that has an "intrinsic size", which is the size it wants to be if that is
- * within the constraints given by the parent. The intrinsic size can be set with the
- * {@code android:width} and {@code android:height} attributes in XML.
+ * within the constraints given by the parent. The intrinsic size can be set with the {@code
+ * android:width} and {@code android:height} attributes in XML.
*
- * Note that for the intrinsic size to be meaningful, {@code android:layout_width} and/or
- * {@code android:layout_height} will need to be {@code wrap_content}.
+ * <p>Note that for the intrinsic size to be meaningful, {@code android:layout_width} and/or {@code
+ * android:layout_height} will need to be {@code wrap_content}.
*/
public class IntrinsicSizeFrameLayout extends FrameLayout {
- private int mIntrinsicHeight = 0;
- private int mIntrinsicWidth = 0;
+ private int intrinsicHeight = 0;
+ private int intrinsicWidth = 0;
- public IntrinsicSizeFrameLayout(Context context) {
- super(context);
- init(context, null, 0);
- }
+ public IntrinsicSizeFrameLayout(Context context) {
+ super(context);
+ init(context, null, 0);
+ }
- public IntrinsicSizeFrameLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs, 0);
- }
+ public IntrinsicSizeFrameLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs, 0);
+ }
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public IntrinsicSizeFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs, defStyleAttr);
- }
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public IntrinsicSizeFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs, defStyleAttr);
+ }
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- final TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.SuwIntrinsicSizeFrameLayout, defStyleAttr, 0);
- mIntrinsicHeight =
- a.getDimensionPixelSize(R.styleable.SuwIntrinsicSizeFrameLayout_android_height, 0);
- mIntrinsicWidth =
- a.getDimensionPixelSize(R.styleable.SuwIntrinsicSizeFrameLayout_android_width, 0);
- a.recycle();
- }
+ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
+ final TypedArray a =
+ context.obtainStyledAttributes(
+ attrs, R.styleable.SuwIntrinsicSizeFrameLayout, defStyleAttr, 0);
+ intrinsicHeight =
+ a.getDimensionPixelSize(R.styleable.SuwIntrinsicSizeFrameLayout_android_height, 0);
+ intrinsicWidth =
+ a.getDimensionPixelSize(R.styleable.SuwIntrinsicSizeFrameLayout_android_width, 0);
+ a.recycle();
+ }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(getIntrinsicMeasureSpec(widthMeasureSpec, mIntrinsicWidth),
- getIntrinsicMeasureSpec(heightMeasureSpec, mIntrinsicHeight));
- }
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(
+ getIntrinsicMeasureSpec(widthMeasureSpec, intrinsicWidth),
+ getIntrinsicMeasureSpec(heightMeasureSpec, intrinsicHeight));
+ }
- private int getIntrinsicMeasureSpec(int measureSpec, int intrinsicSize) {
- if (intrinsicSize <= 0) {
- // Intrinsic size is not set, just return the original spec
- return measureSpec;
- }
- final int mode = MeasureSpec.getMode(measureSpec);
- final int size = MeasureSpec.getSize(measureSpec);
- if (mode == MeasureSpec.UNSPECIFIED) {
- // Parent did not give any constraint, so we'll be the intrinsic size
- return MeasureSpec.makeMeasureSpec(mIntrinsicHeight, MeasureSpec.EXACTLY);
- } else if (mode == MeasureSpec.AT_MOST) {
- // If intrinsic size is within parents constraint, take the intrinsic size.
- // Otherwise take the parents size because that's closest to the intrinsic size.
- return MeasureSpec.makeMeasureSpec(Math.min(size, mIntrinsicHeight),
- MeasureSpec.EXACTLY);
- }
- // Parent specified EXACTLY, or in all other cases, just return the original spec
- return measureSpec;
+ private int getIntrinsicMeasureSpec(int measureSpec, int intrinsicSize) {
+ if (intrinsicSize <= 0) {
+ // Intrinsic size is not set, just return the original spec
+ return measureSpec;
+ }
+ final int mode = MeasureSpec.getMode(measureSpec);
+ final int size = MeasureSpec.getSize(measureSpec);
+ if (mode == MeasureSpec.UNSPECIFIED) {
+ // Parent did not give any constraint, so we'll be the intrinsic size
+ return MeasureSpec.makeMeasureSpec(intrinsicHeight, MeasureSpec.EXACTLY);
+ } else if (mode == MeasureSpec.AT_MOST) {
+ // If intrinsic size is within parents constraint, take the intrinsic size.
+ // Otherwise take the parents size because that's closest to the intrinsic size.
+ return MeasureSpec.makeMeasureSpec(Math.min(size, intrinsicHeight), MeasureSpec.EXACTLY);
}
+ // Parent specified EXACTLY, or in all other cases, just return the original spec
+ return measureSpec;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/NavigationBar.java b/library/main/src/com/android/setupwizardlib/view/NavigationBar.java
index 9971bac..1044e56 100644
--- a/library/main/src/com/android/setupwizardlib/view/NavigationBar.java
+++ b/library/main/src/com/android/setupwizardlib/view/NavigationBar.java
@@ -21,14 +21,12 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build.VERSION_CODES;
+import androidx.annotation.StyleableRes;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
-
-import androidx.annotation.StyleableRes;
-
import com.android.setupwizardlib.R;
/**
@@ -40,104 +38,105 @@ import com.android.setupwizardlib.R;
*/
public class NavigationBar extends LinearLayout implements View.OnClickListener {
- /**
- * An interface to listen to events of the navigation bar, namely when the user clicks on the
- * back or next button.
- */
- public interface NavigationBarListener {
- void onNavigateBack();
- void onNavigateNext();
+ /**
+ * An interface to listen to events of the navigation bar, namely when the user clicks on the back
+ * or next button.
+ */
+ public interface NavigationBarListener {
+ void onNavigateBack();
+
+ void onNavigateNext();
+ }
+
+ private static int getNavbarTheme(Context context) {
+ // Normally we can automatically guess the theme by comparing the foreground color against
+ // the background color. But we also allow specifying explicitly using suwNavBarTheme.
+ TypedArray attributes =
+ context.obtainStyledAttributes(
+ new int[] {
+ R.attr.suwNavBarTheme, android.R.attr.colorForeground, android.R.attr.colorBackground
+ });
+ @StyleableRes int suwNavBarTheme = 0;
+ @StyleableRes int colorForeground = 1;
+ @StyleableRes int colorBackground = 2;
+ int theme = attributes.getResourceId(suwNavBarTheme, 0);
+ if (theme == 0) {
+ // Compare the value of the foreground against the background color to see if current
+ // theme is light-on-dark or dark-on-light.
+ float[] foregroundHsv = new float[3];
+ float[] backgroundHsv = new float[3];
+ Color.colorToHSV(attributes.getColor(colorForeground, 0), foregroundHsv);
+ Color.colorToHSV(attributes.getColor(colorBackground, 0), backgroundHsv);
+ boolean isDarkBg = foregroundHsv[2] > backgroundHsv[2];
+ theme = isDarkBg ? R.style.SuwNavBarThemeDark : R.style.SuwNavBarThemeLight;
}
-
- private static int getNavbarTheme(Context context) {
- // Normally we can automatically guess the theme by comparing the foreground color against
- // the background color. But we also allow specifying explicitly using suwNavBarTheme.
- TypedArray attributes = context.obtainStyledAttributes(
- new int[] {
- R.attr.suwNavBarTheme,
- android.R.attr.colorForeground,
- android.R.attr.colorBackground });
- @StyleableRes int suwNavBarTheme = 0;
- @StyleableRes int colorForeground = 1;
- @StyleableRes int colorBackground = 2;
- int theme = attributes.getResourceId(suwNavBarTheme, 0);
- if (theme == 0) {
- // Compare the value of the foreground against the background color to see if current
- // theme is light-on-dark or dark-on-light.
- float[] foregroundHsv = new float[3];
- float[] backgroundHsv = new float[3];
- Color.colorToHSV(attributes.getColor(colorForeground, 0), foregroundHsv);
- Color.colorToHSV(attributes.getColor(colorBackground, 0), backgroundHsv);
- boolean isDarkBg = foregroundHsv[2] > backgroundHsv[2];
- theme = isDarkBg ? R.style.SuwNavBarThemeDark : R.style.SuwNavBarThemeLight;
- }
- attributes.recycle();
- return theme;
- }
-
- private static Context getThemedContext(Context context) {
- final int theme = getNavbarTheme(context);
- return new ContextThemeWrapper(context, theme);
+ attributes.recycle();
+ return theme;
+ }
+
+ private static Context getThemedContext(Context context) {
+ final int theme = getNavbarTheme(context);
+ return new ContextThemeWrapper(context, theme);
+ }
+
+ private Button nextButton;
+ private Button backButton;
+ private Button moreButton;
+ private NavigationBarListener listener;
+
+ public NavigationBar(Context context) {
+ super(getThemedContext(context));
+ init();
+ }
+
+ public NavigationBar(Context context, AttributeSet attrs) {
+ super(getThemedContext(context), attrs);
+ init();
+ }
+
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public NavigationBar(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(getThemedContext(context), attrs, defStyleAttr);
+ init();
+ }
+
+ // All the constructors delegate to this init method. The 3-argument constructor is not
+ // available in LinearLayout before v11, so call super with the exact same arguments.
+ private void init() {
+ View.inflate(getContext(), R.layout.suw_navbar_view, this);
+ nextButton = (Button) findViewById(R.id.suw_navbar_next);
+ backButton = (Button) findViewById(R.id.suw_navbar_back);
+ moreButton = (Button) findViewById(R.id.suw_navbar_more);
+ }
+
+ public Button getBackButton() {
+ return backButton;
+ }
+
+ public Button getNextButton() {
+ return nextButton;
+ }
+
+ public Button getMoreButton() {
+ return moreButton;
+ }
+
+ public void setNavigationBarListener(NavigationBarListener listener) {
+ this.listener = listener;
+ if (this.listener != null) {
+ getBackButton().setOnClickListener(this);
+ getNextButton().setOnClickListener(this);
}
-
- private Button mNextButton;
- private Button mBackButton;
- private Button mMoreButton;
- private NavigationBarListener mListener;
-
- public NavigationBar(Context context) {
- super(getThemedContext(context));
- init();
- }
-
- public NavigationBar(Context context, AttributeSet attrs) {
- super(getThemedContext(context), attrs);
- init();
- }
-
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public NavigationBar(Context context, AttributeSet attrs, int defStyleAttr) {
- super(getThemedContext(context), attrs, defStyleAttr);
- init();
- }
-
- // All the constructors delegate to this init method. The 3-argument constructor is not
- // available in LinearLayout before v11, so call super with the exact same arguments.
- private void init() {
- View.inflate(getContext(), R.layout.suw_navbar_view, this);
- mNextButton = (Button) findViewById(R.id.suw_navbar_next);
- mBackButton = (Button) findViewById(R.id.suw_navbar_back);
- mMoreButton = (Button) findViewById(R.id.suw_navbar_more);
- }
-
- public Button getBackButton() {
- return mBackButton;
- }
-
- public Button getNextButton() {
- return mNextButton;
- }
-
- public Button getMoreButton() {
- return mMoreButton;
- }
-
- public void setNavigationBarListener(NavigationBarListener listener) {
- mListener = listener;
- if (mListener != null) {
- getBackButton().setOnClickListener(this);
- getNextButton().setOnClickListener(this);
- }
- }
-
- @Override
- public void onClick(View view) {
- if (mListener != null) {
- if (view == getBackButton()) {
- mListener.onNavigateBack();
- } else if (view == getNextButton()) {
- mListener.onNavigateNext();
- }
- }
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (listener != null) {
+ if (view == getBackButton()) {
+ listener.onNavigateBack();
+ } else if (view == getNextButton()) {
+ listener.onNavigateNext();
+ }
}
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/StatusBarBackgroundLayout.java b/library/main/src/com/android/setupwizardlib/view/StatusBarBackgroundLayout.java
index fe0bc8f..dd8c27f 100644
--- a/library/main/src/com/android/setupwizardlib/view/StatusBarBackgroundLayout.java
+++ b/library/main/src/com/android/setupwizardlib/view/StatusBarBackgroundLayout.java
@@ -26,7 +26,6 @@ import android.os.Build.VERSION_CODES;
import android.util.AttributeSet;
import android.view.WindowInsets;
import android.widget.FrameLayout;
-
import com.android.setupwizardlib.R;
/**
@@ -40,74 +39,75 @@ import com.android.setupwizardlib.R;
*/
public class StatusBarBackgroundLayout extends FrameLayout {
- private Drawable mStatusBarBackground;
- private Object mLastInsets; // Use generic Object type for compatibility
+ private Drawable statusBarBackground;
+ private Object lastInsets; // Use generic Object type for compatibility
- public StatusBarBackgroundLayout(Context context) {
- super(context);
- init(context, null, 0);
- }
+ public StatusBarBackgroundLayout(Context context) {
+ super(context);
+ init(context, null, 0);
+ }
- public StatusBarBackgroundLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs, 0);
- }
+ public StatusBarBackgroundLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs, 0);
+ }
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public StatusBarBackgroundLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs, defStyleAttr);
- }
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public StatusBarBackgroundLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs, defStyleAttr);
+ }
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- final TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.SuwStatusBarBackgroundLayout, defStyleAttr, 0);
- final Drawable statusBarBackground =
- a.getDrawable(R.styleable.SuwStatusBarBackgroundLayout_suwStatusBarBackground);
- setStatusBarBackground(statusBarBackground);
- a.recycle();
- }
+ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
+ final TypedArray a =
+ context.obtainStyledAttributes(
+ attrs, R.styleable.SuwStatusBarBackgroundLayout, defStyleAttr, 0);
+ final Drawable statusBarBackground =
+ a.getDrawable(R.styleable.SuwStatusBarBackgroundLayout_suwStatusBarBackground);
+ setStatusBarBackground(statusBarBackground);
+ a.recycle();
+ }
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- if (mLastInsets == null) {
- requestApplyInsets();
- }
- }
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ if (lastInsets == null) {
+ requestApplyInsets();
+ }
}
+ }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- if (mLastInsets != null) {
- final int insetTop = ((WindowInsets) mLastInsets).getSystemWindowInsetTop();
- if (insetTop > 0) {
- mStatusBarBackground.setBounds(0, 0, getWidth(), insetTop);
- mStatusBarBackground.draw(canvas);
- }
- }
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ if (lastInsets != null) {
+ final int insetTop = ((WindowInsets) lastInsets).getSystemWindowInsetTop();
+ if (insetTop > 0) {
+ statusBarBackground.setBounds(0, 0, getWidth(), insetTop);
+ statusBarBackground.draw(canvas);
}
+ }
}
+ }
- public void setStatusBarBackground(Drawable background) {
- mStatusBarBackground = background;
- if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- setWillNotDraw(background == null);
- setFitsSystemWindows(background != null);
- invalidate();
- }
+ public void setStatusBarBackground(Drawable background) {
+ statusBarBackground = background;
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ setWillNotDraw(background == null);
+ setFitsSystemWindows(background != null);
+ invalidate();
}
+ }
- public Drawable getStatusBarBackground() {
- return mStatusBarBackground;
- }
+ public Drawable getStatusBarBackground() {
+ return statusBarBackground;
+ }
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- mLastInsets = insets;
- return super.onApplyWindowInsets(insets);
- }
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ lastInsets = insets;
+ return super.onApplyWindowInsets(insets);
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/StickyHeaderListView.java b/library/main/src/com/android/setupwizardlib/view/StickyHeaderListView.java
index 58274f6..c226f29 100644
--- a/library/main/src/com/android/setupwizardlib/view/StickyHeaderListView.java
+++ b/library/main/src/com/android/setupwizardlib/view/StickyHeaderListView.java
@@ -29,7 +29,6 @@ import android.view.View;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ListView;
-
import com.android.setupwizardlib.R;
/**
@@ -39,125 +38,129 @@ import com.android.setupwizardlib.R;
* when the sticky element hits the top of the view.
*
* <p>There are a few things to note:
+ *
* <ol>
* <li>The two supported scenarios are StickyHeaderListView -> Header (stickyContainer) -> sticky,
- * and StickyHeaderListView -> Header (sticky). The arrow (->) represents parent/child
- * relationship and must be immediate child.
+ * and StickyHeaderListView -> Header (sticky). The arrow (->) represents parent/child
+ * relationship and must be immediate child.
* <li>The view does not work well with padding. b/16190933
* <li>If fitsSystemWindows is true, then this will offset the sticking position by the height of
- * the system decorations at the top of the screen.
+ * the system decorations at the top of the screen.
* </ol>
*
* @see StickyHeaderScrollView
*/
public class StickyHeaderListView extends ListView {
- private View mSticky;
- private View mStickyContainer;
- private int mStatusBarInset = 0;
- private RectF mStickyRect = new RectF();
-
- public StickyHeaderListView(Context context) {
- super(context);
- init(null, android.R.attr.listViewStyle);
+ private View sticky;
+ private View stickyContainer;
+ private int statusBarInset = 0;
+ private final RectF stickyRect = new RectF();
+
+ public StickyHeaderListView(Context context) {
+ super(context);
+ init(null, android.R.attr.listViewStyle);
+ }
+
+ public StickyHeaderListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, android.R.attr.listViewStyle);
+ }
+
+ public StickyHeaderListView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ final TypedArray a =
+ getContext()
+ .obtainStyledAttributes(attrs, R.styleable.SuwStickyHeaderListView, defStyleAttr, 0);
+ int headerResId = a.getResourceId(R.styleable.SuwStickyHeaderListView_suwHeader, 0);
+ if (headerResId != 0) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ View header = inflater.inflate(headerResId, this, false);
+ addHeaderView(header, null, false);
}
-
- public StickyHeaderListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs, android.R.attr.listViewStyle);
+ a.recycle();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (sticky == null) {
+ updateStickyView();
}
-
- public StickyHeaderListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(attrs, defStyleAttr);
+ }
+
+ public void updateStickyView() {
+ sticky = findViewWithTag("sticky");
+ stickyContainer = findViewWithTag("stickyContainer");
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (stickyRect.contains(ev.getX(), ev.getY())) {
+ ev.offsetLocation(-stickyRect.left, -stickyRect.top);
+ return stickyContainer.dispatchTouchEvent(ev);
+ } else {
+ return super.dispatchTouchEvent(ev);
}
-
- private void init(AttributeSet attrs, int defStyleAttr) {
- final TypedArray a = getContext().obtainStyledAttributes(attrs,
- R.styleable.SuwStickyHeaderListView, defStyleAttr, 0);
- int headerResId = a.getResourceId(R.styleable.SuwStickyHeaderListView_suwHeader, 0);
- if (headerResId != 0) {
- LayoutInflater inflater = LayoutInflater.from(getContext());
- View header = inflater.inflate(headerResId, this, false);
- addHeaderView(header, null, false);
- }
- a.recycle();
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- if (mSticky == null) {
- updateStickyView();
- }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ if (sticky != null) {
+ final int saveCount = canvas.save();
+ // The view to draw when sticking to the top
+ final View drawTarget = stickyContainer != null ? stickyContainer : sticky;
+ // The offset to draw the view at when sticky
+ final int drawOffset = stickyContainer != null ? sticky.getTop() : 0;
+ // Position of the draw target, relative to the outside of the scrollView
+ final int drawTop = drawTarget.getTop();
+ if (drawTop + drawOffset < statusBarInset || !drawTarget.isShown()) {
+ // ListView does not translate the canvas, so we can simply draw at the top
+ stickyRect.set(
+ 0,
+ -drawOffset + statusBarInset,
+ drawTarget.getWidth(),
+ drawTarget.getHeight() - drawOffset + statusBarInset);
+ canvas.translate(0, stickyRect.top);
+ canvas.clipRect(0, 0, drawTarget.getWidth(), drawTarget.getHeight());
+ drawTarget.draw(canvas);
+ } else {
+ stickyRect.setEmpty();
+ }
+ canvas.restoreToCount(saveCount);
}
-
- public void updateStickyView() {
- mSticky = findViewWithTag("sticky");
- mStickyContainer = findViewWithTag("stickyContainer");
+ }
+
+ @Override
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if (getFitsSystemWindows()) {
+ statusBarInset = insets.getSystemWindowInsetTop();
+ insets.replaceSystemWindowInsets(
+ insets.getSystemWindowInsetLeft(),
+ 0, /* top */
+ insets.getSystemWindowInsetRight(),
+ insets.getSystemWindowInsetBottom());
}
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (mStickyRect.contains(ev.getX(), ev.getY())) {
- ev.offsetLocation(-mStickyRect.left, -mStickyRect.top);
- return mStickyContainer.dispatchTouchEvent(ev);
- } else {
- return super.dispatchTouchEvent(ev);
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- if (mSticky != null) {
- final int saveCount = canvas.save();
- // The view to draw when sticking to the top
- final View drawTarget = mStickyContainer != null ? mStickyContainer : mSticky;
- // The offset to draw the view at when sticky
- final int drawOffset = mStickyContainer != null ? mSticky.getTop() : 0;
- // Position of the draw target, relative to the outside of the scrollView
- final int drawTop = drawTarget.getTop();
- if (drawTop + drawOffset < mStatusBarInset || !drawTarget.isShown()) {
- // ListView does not translate the canvas, so we can simply draw at the top
- mStickyRect.set(0, -drawOffset + mStatusBarInset, drawTarget.getWidth(),
- drawTarget.getHeight() - drawOffset + mStatusBarInset);
- canvas.translate(0, mStickyRect.top);
- canvas.clipRect(0, 0, drawTarget.getWidth(), drawTarget.getHeight());
- drawTarget.draw(canvas);
- } else {
- mStickyRect.setEmpty();
- }
- canvas.restoreToCount(saveCount);
- }
- }
-
- @Override
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- if (getFitsSystemWindows()) {
- mStatusBarInset = insets.getSystemWindowInsetTop();
- insets.replaceSystemWindowInsets(
- insets.getSystemWindowInsetLeft(),
- 0, /* top */
- insets.getSystemWindowInsetRight(),
- insets.getSystemWindowInsetBottom()
- );
- }
- return insets;
- }
-
- @Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
-
- // Decoration-only headers should not count as an item for accessibility, adjust the
- // accessibility event to account for that.
- final int numberOfHeaders = mSticky != null ? 1 : 0;
- event.setItemCount(event.getItemCount() - numberOfHeaders);
- event.setFromIndex(Math.max(event.getFromIndex() - numberOfHeaders, 0));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- event.setToIndex(Math.max(event.getToIndex() - numberOfHeaders, 0));
- }
+ return insets;
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+
+ // Decoration-only headers should not count as an item for accessibility, adjust the
+ // accessibility event to account for that.
+ final int numberOfHeaders = sticky != null ? 1 : 0;
+ event.setItemCount(event.getItemCount() - numberOfHeaders);
+ event.setFromIndex(Math.max(event.getFromIndex() - numberOfHeaders, 0));
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ event.setToIndex(Math.max(event.getToIndex() - numberOfHeaders, 0));
}
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/StickyHeaderScrollView.java b/library/main/src/com/android/setupwizardlib/view/StickyHeaderScrollView.java
index ca47446..9fd7b0c 100644
--- a/library/main/src/com/android/setupwizardlib/view/StickyHeaderScrollView.java
+++ b/library/main/src/com/android/setupwizardlib/view/StickyHeaderScrollView.java
@@ -30,12 +30,13 @@ import android.view.WindowInsets;
* drawn when the sticky element hits the top of the view.
*
* <p>There are a few things to note:
+ *
* <ol>
* <li>The two supported scenarios are StickyHeaderScrollView -> subview (stickyContainer) ->
- * sticky, and StickyHeaderScrollView -> container -> subview (sticky).
- * The arrow (->) represents parent/child relationship and must be immediate child.
+ * sticky, and StickyHeaderScrollView -> container -> subview (sticky). The arrow (->)
+ * represents parent/child relationship and must be immediate child.
* <li>If fitsSystemWindows is true, then this will offset the sticking position by the height of
- * the system decorations at the top of the screen.
+ * the system decorations at the top of the screen.
* <li>For versions before Honeycomb, this will behave like a regular ScrollView.
* </ol>
*
@@ -43,75 +44,75 @@ import android.view.WindowInsets;
*/
public class StickyHeaderScrollView extends BottomScrollView {
- private View mSticky;
- private View mStickyContainer;
- private int mStatusBarInset = 0;
+ private View sticky;
+ private View stickyContainer;
+ private int statusBarInset = 0;
- public StickyHeaderScrollView(Context context) {
- super(context);
- }
+ public StickyHeaderScrollView(Context context) {
+ super(context);
+ }
- public StickyHeaderScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
+ public StickyHeaderScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
- public StickyHeaderScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
+ public StickyHeaderScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- if (mSticky == null) {
- updateStickyView();
- }
- updateStickyHeaderPosition();
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (sticky == null) {
+ updateStickyView();
}
+ updateStickyHeaderPosition();
+ }
- public void updateStickyView() {
- mSticky = findViewWithTag("sticky");
- mStickyContainer = findViewWithTag("stickyContainer");
- }
+ public void updateStickyView() {
+ sticky = findViewWithTag("sticky");
+ stickyContainer = findViewWithTag("stickyContainer");
+ }
- private void updateStickyHeaderPosition() {
- // Note: for pre-Honeycomb the header will not be moved, so this ScrollView essentially
- // behaves like a normal BottomScrollView.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- if (mSticky != null) {
- // The view to draw when sticking to the top
- final View drawTarget = mStickyContainer != null ? mStickyContainer : mSticky;
- // The offset to draw the view at when sticky
- final int drawOffset = mStickyContainer != null ? mSticky.getTop() : 0;
- // Position of the draw target, relative to the outside of the scrollView
- final int drawTop = drawTarget.getTop() - getScrollY();
- if (drawTop + drawOffset < mStatusBarInset || !drawTarget.isShown()) {
- // ScrollView translates the whole canvas so we have to compensate for that
- drawTarget.setTranslationY(getScrollY() - drawOffset);
- } else {
- drawTarget.setTranslationY(0);
- }
- }
+ private void updateStickyHeaderPosition() {
+ // Note: for pre-Honeycomb the header will not be moved, so this ScrollView essentially
+ // behaves like a normal BottomScrollView.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ if (sticky != null) {
+ // The view to draw when sticking to the top
+ final View drawTarget = stickyContainer != null ? stickyContainer : sticky;
+ // The offset to draw the view at when sticky
+ final int drawOffset = stickyContainer != null ? sticky.getTop() : 0;
+ // Position of the draw target, relative to the outside of the scrollView
+ final int drawTop = drawTarget.getTop() - getScrollY();
+ if (drawTop + drawOffset < statusBarInset || !drawTarget.isShown()) {
+ // ScrollView translates the whole canvas so we have to compensate for that
+ drawTarget.setTranslationY(getScrollY() - drawOffset);
+ } else {
+ drawTarget.setTranslationY(0);
}
+ }
}
+ }
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt) {
- super.onScrollChanged(l, t, oldl, oldt);
- updateStickyHeaderPosition();
- }
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ updateStickyHeaderPosition();
+ }
- @Override
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- if (getFitsSystemWindows()) {
- mStatusBarInset = insets.getSystemWindowInsetTop();
- insets = insets.replaceSystemWindowInsets(
- insets.getSystemWindowInsetLeft(),
- 0, /* top */
- insets.getSystemWindowInsetRight(),
- insets.getSystemWindowInsetBottom()
- );
- }
- return insets;
+ @Override
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if (getFitsSystemWindows()) {
+ statusBarInset = insets.getSystemWindowInsetTop();
+ insets =
+ insets.replaceSystemWindowInsets(
+ insets.getSystemWindowInsetLeft(),
+ 0, /* top */
+ insets.getSystemWindowInsetRight(),
+ insets.getSystemWindowInsetBottom());
}
+ return insets;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/view/TouchableMovementMethod.java b/library/main/src/com/android/setupwizardlib/view/TouchableMovementMethod.java
index 10e91f4..526883c 100644
--- a/library/main/src/com/android/setupwizardlib/view/TouchableMovementMethod.java
+++ b/library/main/src/com/android/setupwizardlib/view/TouchableMovementMethod.java
@@ -24,60 +24,56 @@ import android.view.MotionEvent;
import android.widget.TextView;
/**
- * A movement method that tracks the last result of whether touch events are handled. This is
- * used to patch the return value of {@link TextView#onTouchEvent} so that it consumes the touch
- * events only when the movement method says the event is consumed.
+ * A movement method that tracks the last result of whether touch events are handled. This is used
+ * to patch the return value of {@link TextView#onTouchEvent} so that it consumes the touch events
+ * only when the movement method says the event is consumed.
*/
public interface TouchableMovementMethod {
- /**
- * @return The last touch event received in {@link MovementMethod#onTouchEvent}
- */
- MotionEvent getLastTouchEvent();
+ /** @return The last touch event received in {@link MovementMethod#onTouchEvent} */
+ MotionEvent getLastTouchEvent();
- /**
- * @return The return value of the last {@link MovementMethod#onTouchEvent}, or whether the
- * last touch event should be considered handled by the text view
- */
- boolean isLastTouchEventHandled();
+ /**
+ * @return The return value of the last {@link MovementMethod#onTouchEvent}, or whether the last
+ * touch event should be considered handled by the text view
+ */
+ boolean isLastTouchEventHandled();
- /**
- * An extension of LinkMovementMethod that tracks whether the event is handled when it is
- * touched.
- */
- class TouchableLinkMovementMethod extends LinkMovementMethod
- implements TouchableMovementMethod {
+ /**
+ * An extension of LinkMovementMethod that tracks whether the event is handled when it is touched.
+ */
+ class TouchableLinkMovementMethod extends LinkMovementMethod implements TouchableMovementMethod {
- public static TouchableLinkMovementMethod getInstance() {
- return new TouchableLinkMovementMethod();
- }
+ public static TouchableLinkMovementMethod getInstance() {
+ return new TouchableLinkMovementMethod();
+ }
- boolean mLastEventResult = false;
- MotionEvent mLastEvent;
+ boolean lastEventResult = false;
+ MotionEvent lastEvent;
- @Override
- public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
- mLastEvent = event;
- boolean result = super.onTouchEvent(widget, buffer, event);
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- // Unfortunately, LinkMovementMethod extends ScrollMovementMethod, and it always
- // consume the down event. So here we use the selection instead as a hint of whether
- // the down event landed on a link.
- mLastEventResult = Selection.getSelectionStart(buffer) != -1;
- } else {
- mLastEventResult = result;
- }
- return result;
- }
+ @Override
+ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
+ lastEvent = event;
+ boolean result = super.onTouchEvent(widget, buffer, event);
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ // Unfortunately, LinkMovementMethod extends ScrollMovementMethod, and it always
+ // consume the down event. So here we use the selection instead as a hint of whether
+ // the down event landed on a link.
+ lastEventResult = Selection.getSelectionStart(buffer) != -1;
+ } else {
+ lastEventResult = result;
+ }
+ return result;
+ }
- @Override
- public MotionEvent getLastTouchEvent() {
- return mLastEvent;
- }
+ @Override
+ public MotionEvent getLastTouchEvent() {
+ return lastEvent;
+ }
- @Override
- public boolean isLastTouchEventHandled() {
- return mLastEventResult;
- }
+ @Override
+ public boolean isLastTouchEventHandled() {
+ return lastEventResult;
}
+ }
}
diff --git a/navigationbar/res/drawable/setup_wizard_navbar_ic_back.xml b/library/platform/AndroidManifest.xml
index 260e913..9aa24dc 100644
--- a/navigationbar/res/drawable/setup_wizard_navbar_ic_back.xml
+++ b/library/platform/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ 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.
@@ -14,15 +14,10 @@
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:autoMirrored="true"
- android:width="@dimen/setup_wizard_navbar_ic_intrinsic_size"
- android:height="@dimen/setup_wizard_navbar_ic_intrinsic_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="?attr/setup_wizard_navbar_text_color"
- android:pathData="M15.4,7.4l-1.4,-1.4 -6,6 6,6 1.4,-1.4 -4.6,-4.6z" />
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.setupwizardlib">
-</vector>
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+</manifest>
diff --git a/library/platform/res/values-v27/styles.xml b/library/platform/res/values-v27/styles.xml
index 6e36919..70101c9 100644
--- a/library/platform/res/values-v27/styles.xml
+++ b/library/platform/res/values-v27/styles.xml
@@ -44,6 +44,7 @@
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwCardBackground">@drawable/suw_card_bg</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -75,6 +76,7 @@
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwCardBackground">@drawable/suw_card_bg</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -109,7 +111,8 @@
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonCornerRadius">@dimen/suw_glif_button_corner_radius</item>
- <item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonFontFamily">sans-serif-medium</item>
+ <item name="suwButtonHighlightAlpha">0.24</item>
<item name="suwColorPrimary">?android:attr/colorPrimary</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -145,7 +148,8 @@
<item name="suwButtonAllCaps">true</item>
<item name="suwButtonCornerRadius">@dimen/suw_glif_button_corner_radius</item>
- <item name="suwButtonFontFamily">sans-serif</item>
+ <item name="suwButtonFontFamily">sans-serif-medium</item>
+ <item name="suwButtonHighlightAlpha">0.12</item>
<item name="suwColorPrimary">?android:attr/colorPrimary</item>
<item name="suwFillContentLayoutStyle">@style/SuwFillContentLayout</item>
<item name="suwDividerInsetEnd">0dp</item>
@@ -218,4 +222,11 @@
<item name="android:colorControlHighlight">@color/suw_flat_button_highlight</item>
</style>
+ <!-- Ignore UnusedResources: used by clients -->
+ <style name="SuwGlifButton.Tertiary"
+ parent="SuwGlifButton.BaseTertiary"
+ tools:ignore="UnusedResources">
+ <item name="android:fontFamily">sans-serif-medium</item>
+ </style>
+
</resources>
diff --git a/library/platform/src/com/android/setupwizardlib/view/NavigationBarButton.java b/library/platform/src/com/android/setupwizardlib/view/NavigationBarButton.java
index 45d3737..5d14aa7 100644
--- a/library/platform/src/com/android/setupwizardlib/view/NavigationBarButton.java
+++ b/library/platform/src/com/android/setupwizardlib/view/NavigationBarButton.java
@@ -22,11 +22,11 @@ import android.widget.Button;
public class NavigationBarButton extends Button {
- public NavigationBarButton(Context context) {
- super(context);
- }
+ public NavigationBarButton(Context context) {
+ super(context);
+ }
- public NavigationBarButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
+ public NavigationBarButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
}
diff --git a/library/platform/src/com/android/setupwizardlib/view/RichTextView.java b/library/platform/src/com/android/setupwizardlib/view/RichTextView.java
index fa68a68..7eb29c6 100644
--- a/library/platform/src/com/android/setupwizardlib/view/RichTextView.java
+++ b/library/platform/src/com/android/setupwizardlib/view/RichTextView.java
@@ -27,15 +27,14 @@ 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.LinkSpan.OnLinkClickListener;
import com.android.setupwizardlib.span.SpanHelper;
import com.android.setupwizardlib.view.TouchableMovementMethod.TouchableLinkMovementMethod;
/**
- * An extension of TextView that automatically replaces the annotation tags as specified in
- * {@link SpanHelper#replaceSpan(android.text.Spannable, Object, Object)}
+ * An extension of TextView that automatically replaces the annotation tags as specified in {@link
+ * SpanHelper#replaceSpan(android.text.Spannable, Object, Object)}
*
* <p>Note: The accessibility interaction for ClickableSpans (and therefore LinkSpans) are built
* into platform in O, although the interaction paradigm is different. (See b/17726921). In this
@@ -44,133 +43,133 @@ import com.android.setupwizardlib.view.TouchableMovementMethod.TouchableLinkMove
*/
public class RichTextView extends TextView implements OnLinkClickListener {
- /* 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;
+ /* 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>&lt;annotation textAppearance="TextAppearance.FooBar"&gt; will create a {@link
+ * android.text.style.TextAppearanceSpan} with @style/TextAppearance.FooBar
+ * </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 text;
- }
-
- /* non-static section */
-
- private OnLinkClickListener mOnLinkClickListener;
-
- public RichTextView(Context context) {
- super(context);
- }
-
- public RichTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ }
+ return spannable;
}
-
- @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(TouchableLinkMovementMethod.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);
- // Do not "reveal" (i.e. scroll to) this view when this view is focused. Since this view is
- // focusable in touch mode, we may be focused when the screen is first shown, and starting
- // a screen halfway scrolled down is confusing to the user.
- setRevealOnFocusHint(false);
- setFocusableInTouchMode(hasLinks);
+ return text;
+ }
+
+ /* non-static section */
+
+ private OnLinkClickListener mOnLinkClickListener;
+
+ public RichTextView(Context context) {
+ super(context);
+ }
+
+ public RichTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @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(TouchableLinkMovementMethod.getInstance());
+ } else {
+ setMovementMethod(null);
}
-
- 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;
+ // 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);
+ // Do not "reveal" (i.e. scroll to) this view when this view is focused. Since this view is
+ // focusable in touch mode, we may be focused when the screen is first shown, and starting
+ // a screen halfway scrolled down is confusing to the user.
+ setRevealOnFocusHint(false);
+ setFocusableInTouchMode(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;
}
-
- @Override
- @SuppressWarnings("ClickableViewAccessibility") // super.onTouchEvent is called
- public boolean onTouchEvent(MotionEvent event) {
- // Since View#onTouchEvent always return true if the view is clickable (which is the case
- // when a TextView has a movement method), override the implementation to allow the movement
- // method, if it implements TouchableMovementMethod, to say that the touch is not handled,
- // allowing the event to bubble up to the parent view.
- boolean superResult = super.onTouchEvent(event);
- MovementMethod movementMethod = getMovementMethod();
- if (movementMethod instanceof TouchableMovementMethod) {
- TouchableMovementMethod touchableMovementMethod =
- (TouchableMovementMethod) movementMethod;
- if (touchableMovementMethod.getLastTouchEvent() == event) {
- return touchableMovementMethod.isLastTouchEventHandled();
- }
- }
- return superResult;
+ return false;
+ }
+
+ @Override
+ @SuppressWarnings("ClickableViewAccessibility") // super.onTouchEvent is called
+ public boolean onTouchEvent(MotionEvent event) {
+ // Since View#onTouchEvent always return true if the view is clickable (which is the case
+ // when a TextView has a movement method), override the implementation to allow the movement
+ // method, if it implements TouchableMovementMethod, to say that the touch is not handled,
+ // allowing the event to bubble up to the parent view.
+ boolean superResult = super.onTouchEvent(event);
+ MovementMethod movementMethod = getMovementMethod();
+ if (movementMethod instanceof TouchableMovementMethod) {
+ TouchableMovementMethod touchableMovementMethod = (TouchableMovementMethod) movementMethod;
+ if (touchableMovementMethod.getLastTouchEvent() == event) {
+ return touchableMovementMethod.isLastTouchEventHandled();
+ }
}
+ return superResult;
+ }
- public void setOnLinkClickListener(OnLinkClickListener listener) {
- mOnLinkClickListener = listener;
- }
+ public void setOnLinkClickListener(OnLinkClickListener listener) {
+ mOnLinkClickListener = listener;
+ }
- public OnLinkClickListener getOnLinkClickListener() {
- return mOnLinkClickListener;
- }
+ public OnLinkClickListener getOnLinkClickListener() {
+ return mOnLinkClickListener;
+ }
- @Override
- public boolean onLinkClick(LinkSpan span) {
- if (mOnLinkClickListener != null) {
- return mOnLinkClickListener.onLinkClick(span);
- }
- return false;
+ @Override
+ public boolean onLinkClick(LinkSpan span) {
+ if (mOnLinkClickListener != null) {
+ return mOnLinkClickListener.onLinkClick(span);
}
+ return false;
+ }
}
diff --git a/library/platform/test/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java b/library/platform/test/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java
index 3d11e12..212b52c 100644
--- a/library/platform/test/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java
+++ b/library/platform/test/src/com/android/setupwizardlib/test/util/DrawingTestActivity.java
@@ -25,5 +25,4 @@ import android.app.Activity;
*
* @see DrawingTestHelper
*/
-public class DrawingTestActivity extends Activity {
-}
+public class DrawingTestActivity extends Activity {}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/DividerItemDecoration.java b/library/recyclerview/src/com/android/setupwizardlib/DividerItemDecoration.java
index 2db17f8..128ed6b 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/DividerItemDecoration.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/DividerItemDecoration.java
@@ -21,223 +21,207 @@ import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.view.View;
-
import androidx.annotation.IntDef;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
-
+import android.view.View;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* An {@link androidx.recyclerview.widget.RecyclerView.ItemDecoration} for RecyclerView to draw
- * dividers between items. This ItemDecoration will draw the drawable specified by
- * {@link #setDivider(android.graphics.drawable.Drawable)} as the divider in between each item by
- * default, and the behavior of whether the divider is shown can be customized by subclassing
- * {@link com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}.
+ * dividers between items. This ItemDecoration will draw the drawable specified by {@link
+ * #setDivider(android.graphics.drawable.Drawable)} as the divider in between each item by default,
+ * and the behavior of whether the divider is shown can be customized by subclassing {@link
+ * com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}.
*
* <p>Modified from v14 PreferenceFragment.DividerDecoration.
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
- /* static section */
+ /* static section */
+
+ /**
+ * An interface to be implemented by a {@link RecyclerView.ViewHolder} which controls whether
+ * dividers should be shown above and below that item.
+ */
+ public interface DividedViewHolder {
/**
- * An interface to be implemented by a {@link RecyclerView.ViewHolder} which controls whether
- * dividers should be shown above and below that item.
+ * Returns whether divider is allowed above this item. A divider will be shown only if both
+ * items immediately above and below it allows this divider.
*/
- public interface DividedViewHolder {
-
- /**
- * Returns whether divider is allowed above this item. A divider will be shown only if both
- * items immediately above and below it allows this divider.
- */
- boolean isDividerAllowedAbove();
-
- /**
- * Returns whether divider is allowed below this item. A divider will be shown only if both
- * items immediately above and below it allows this divider.
- */
- boolean isDividerAllowedBelow();
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- DIVIDER_CONDITION_EITHER,
- DIVIDER_CONDITION_BOTH})
- public @interface DividerCondition {}
-
- public static final int DIVIDER_CONDITION_EITHER = 0;
- public static final int DIVIDER_CONDITION_BOTH = 1;
+ boolean isDividerAllowedAbove();
/**
- * @deprecated Use {@link #DividerItemDecoration(android.content.Context)}
+ * Returns whether divider is allowed below this item. A divider will be shown only if both
+ * items immediately above and below it allows this divider.
*/
- @Deprecated
- public static DividerItemDecoration getDefault(Context context) {
- return new DividerItemDecoration(context);
- }
-
- /* non-static section */
-
- private Drawable mDivider;
- private int mDividerHeight;
- private int mDividerIntrinsicHeight;
- @DividerCondition
- private int mDividerCondition;
+ boolean isDividerAllowedBelow();
+ }
- public DividerItemDecoration() {
- }
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DIVIDER_CONDITION_EITHER, DIVIDER_CONDITION_BOTH})
+ public @interface DividerCondition {}
- public DividerItemDecoration(Context context) {
- final TypedArray a = context.obtainStyledAttributes(R.styleable.SuwDividerItemDecoration);
- final Drawable divider = a.getDrawable(
- R.styleable.SuwDividerItemDecoration_android_listDivider);
- final int dividerHeight = a.getDimensionPixelSize(
- R.styleable.SuwDividerItemDecoration_android_dividerHeight, 0);
- @DividerCondition final int dividerCondition = a.getInt(
- R.styleable.SuwDividerItemDecoration_suwDividerCondition,
- DIVIDER_CONDITION_EITHER);
- a.recycle();
-
- setDivider(divider);
- setDividerHeight(dividerHeight);
- setDividerCondition(dividerCondition);
- }
+ public static final int DIVIDER_CONDITION_EITHER = 0;
+ public static final int DIVIDER_CONDITION_BOTH = 1;
- @Override
- public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
- if (mDivider == null) {
- return;
- }
- final int childCount = parent.getChildCount();
- final int width = parent.getWidth();
- final int dividerHeight = mDividerHeight != 0 ? mDividerHeight : mDividerIntrinsicHeight;
- for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
- final View view = parent.getChildAt(childViewIndex);
- if (shouldDrawDividerBelow(view, parent)) {
- final int top = (int) ViewCompat.getY(view) + view.getHeight();
- mDivider.setBounds(0, top, width, top + dividerHeight);
- mDivider.draw(c);
- }
- }
- }
+ /** @deprecated Use {@link #DividerItemDecoration(android.content.Context)} */
+ @Deprecated
+ public static DividerItemDecoration getDefault(Context context) {
+ return new DividerItemDecoration(context);
+ }
- @Override
- public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
- RecyclerView.State state) {
- if (shouldDrawDividerBelow(view, parent)) {
- outRect.bottom = mDividerHeight != 0 ? mDividerHeight : mDividerIntrinsicHeight;
- }
- }
+ /* non-static section */
- private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
- final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
- final int index = holder.getLayoutPosition();
- final int lastItemIndex = parent.getAdapter().getItemCount() - 1;
- if (isDividerAllowedBelow(holder)) {
- if (mDividerCondition == DIVIDER_CONDITION_EITHER) {
- // Draw the divider without consulting the next item if we only
- // need permission for either above or below.
- return true;
- }
- } else if (mDividerCondition == DIVIDER_CONDITION_BOTH || index == lastItemIndex) {
- // Don't draw if the current view holder doesn't allow drawing below
- // and the current theme requires permission for both the item below and above.
- // Also, if this is the last item, there is no item below to ask permission
- // for whether to draw a divider above, so don't draw it.
- return false;
- }
- // Require permission from index below to draw the divider.
- if (index < lastItemIndex) {
- final RecyclerView.ViewHolder nextHolder =
- parent.findViewHolderForLayoutPosition(index + 1);
- if (!isDividerAllowedAbove(nextHolder)) {
- // Don't draw if the next view holder doesn't allow drawing above
- return false;
- }
- }
- return true;
- }
-
- /**
- * Whether a divider is allowed above the view holder. The allowed values will be combined
- * according to {@link #getDividerCondition()}. The default implementation delegates to
- * {@link com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}, or simply allows
- * the divider if the view holder doesn't implement {@code DividedViewHolder}. Subclasses can
- * override this to give more information to decide whether a divider should be drawn.
- *
- * @return True if divider is allowed above this view holder.
- */
- protected boolean isDividerAllowedAbove(RecyclerView.ViewHolder viewHolder) {
- return !(viewHolder instanceof DividedViewHolder)
- || ((DividedViewHolder) viewHolder).isDividerAllowedAbove();
- }
+ private Drawable divider;
+ private int dividerHeight;
+ private int dividerIntrinsicHeight;
+ @DividerCondition private int dividerCondition;
- /**
- * Whether a divider is allowed below the view holder. The allowed values will be combined
- * according to {@link #getDividerCondition()}. The default implementation delegates to
- * {@link com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}, or simply allows
- * the divider if the view holder doesn't implement {@code DividedViewHolder}. Subclasses can
- * override this to give more information to decide whether a divider should be drawn.
- *
- * @return True if divider is allowed below this view holder.
- */
- protected boolean isDividerAllowedBelow(RecyclerView.ViewHolder viewHolder) {
- return !(viewHolder instanceof DividedViewHolder)
- || ((DividedViewHolder) viewHolder).isDividerAllowedBelow();
- }
+ public DividerItemDecoration() {}
- /**
- * Sets the drawable to be used as the divider.
- */
- public void setDivider(Drawable divider) {
- if (divider != null) {
- mDividerIntrinsicHeight = divider.getIntrinsicHeight();
- } else {
- mDividerIntrinsicHeight = 0;
- }
- mDivider = divider;
+ public DividerItemDecoration(Context context) {
+ final TypedArray a = context.obtainStyledAttributes(R.styleable.SuwDividerItemDecoration);
+ final Drawable divider =
+ a.getDrawable(R.styleable.SuwDividerItemDecoration_android_listDivider);
+ final int dividerHeight =
+ a.getDimensionPixelSize(R.styleable.SuwDividerItemDecoration_android_dividerHeight, 0);
+ @DividerCondition
+ final int dividerCondition =
+ a.getInt(
+ R.styleable.SuwDividerItemDecoration_suwDividerCondition, DIVIDER_CONDITION_EITHER);
+ a.recycle();
+
+ setDivider(divider);
+ setDividerHeight(dividerHeight);
+ setDividerCondition(dividerCondition);
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ if (divider == null) {
+ return;
}
-
- /**
- * Gets the drawable currently used as the divider.
- */
- public Drawable getDivider() {
- return mDivider;
+ final int childCount = parent.getChildCount();
+ final int width = parent.getWidth();
+ final int dividerHeight = this.dividerHeight != 0 ? this.dividerHeight : dividerIntrinsicHeight;
+ for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
+ final View view = parent.getChildAt(childViewIndex);
+ if (shouldDrawDividerBelow(view, parent)) {
+ final int top = (int) ViewCompat.getY(view) + view.getHeight();
+ divider.setBounds(0, top, width, top + dividerHeight);
+ divider.draw(c);
+ }
}
+ }
- /**
- * Sets the divider height, in pixels.
- */
- public void setDividerHeight(int dividerHeight) {
- mDividerHeight = dividerHeight;
+ @Override
+ public void getItemOffsets(
+ Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+ if (shouldDrawDividerBelow(view, parent)) {
+ outRect.bottom = dividerHeight != 0 ? dividerHeight : dividerIntrinsicHeight;
}
-
- /**
- * Gets the divider height, in pixels.
- */
- public int getDividerHeight() {
- return mDividerHeight;
+ }
+
+ private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
+ final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
+ final int index = holder.getLayoutPosition();
+ final int lastItemIndex = parent.getAdapter().getItemCount() - 1;
+ if (isDividerAllowedBelow(holder)) {
+ if (dividerCondition == DIVIDER_CONDITION_EITHER) {
+ // Draw the divider without consulting the next item if we only
+ // need permission for either above or below.
+ return true;
+ }
+ } else if (dividerCondition == DIVIDER_CONDITION_BOTH || index == lastItemIndex) {
+ // Don't draw if the current view holder doesn't allow drawing below
+ // and the current theme requires permission for both the item below and above.
+ // Also, if this is the last item, there is no item below to ask permission
+ // for whether to draw a divider above, so don't draw it.
+ return false;
}
-
- /**
- * Sets whether the divider needs permission from both the item view holder below
- * and above from where the divider would draw itself or just needs permission from
- * one or the other before drawing itself.
- */
- public void setDividerCondition(@DividerCondition int dividerCondition) {
- mDividerCondition = dividerCondition;
+ // Require permission from index below to draw the divider.
+ if (index < lastItemIndex) {
+ final RecyclerView.ViewHolder nextHolder = parent.findViewHolderForLayoutPosition(index + 1);
+ if (!isDividerAllowedAbove(nextHolder)) {
+ // Don't draw if the next view holder doesn't allow drawing above
+ return false;
+ }
}
-
- /**
- * Gets whether the divider needs permission from both the item view holder below
- * and above from where the divider would draw itself or just needs permission from
- * one or the other before drawing itself.
- */
- @DividerCondition
- public int getDividerCondition() {
- return mDividerCondition;
+ return true;
+ }
+
+ /**
+ * Whether a divider is allowed above the view holder. The allowed values will be combined
+ * according to {@link #getDividerCondition()}. The default implementation delegates to {@link
+ * com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}, or simply allows the
+ * divider if the view holder doesn't implement {@code DividedViewHolder}. Subclasses can override
+ * this to give more information to decide whether a divider should be drawn.
+ *
+ * @return True if divider is allowed above this view holder.
+ */
+ protected boolean isDividerAllowedAbove(RecyclerView.ViewHolder viewHolder) {
+ return !(viewHolder instanceof DividedViewHolder)
+ || ((DividedViewHolder) viewHolder).isDividerAllowedAbove();
+ }
+
+ /**
+ * Whether a divider is allowed below the view holder. The allowed values will be combined
+ * according to {@link #getDividerCondition()}. The default implementation delegates to {@link
+ * com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}, or simply allows the
+ * divider if the view holder doesn't implement {@code DividedViewHolder}. Subclasses can override
+ * this to give more information to decide whether a divider should be drawn.
+ *
+ * @return True if divider is allowed below this view holder.
+ */
+ protected boolean isDividerAllowedBelow(RecyclerView.ViewHolder viewHolder) {
+ return !(viewHolder instanceof DividedViewHolder)
+ || ((DividedViewHolder) viewHolder).isDividerAllowedBelow();
+ }
+
+ /** Sets the drawable to be used as the divider. */
+ public void setDivider(Drawable divider) {
+ if (divider != null) {
+ dividerIntrinsicHeight = divider.getIntrinsicHeight();
+ } else {
+ dividerIntrinsicHeight = 0;
}
+ this.divider = divider;
+ }
+
+ /** Gets the drawable currently used as the divider. */
+ public Drawable getDivider() {
+ return divider;
+ }
+
+ /** Sets the divider height, in pixels. */
+ public void setDividerHeight(int dividerHeight) {
+ this.dividerHeight = dividerHeight;
+ }
+
+ /** Gets the divider height, in pixels. */
+ public int getDividerHeight() {
+ return dividerHeight;
+ }
+
+ /**
+ * Sets whether the divider needs permission from both the item view holder below and above from
+ * where the divider would draw itself or just needs permission from one or the other before
+ * drawing itself.
+ */
+ public void setDividerCondition(@DividerCondition int dividerCondition) {
+ this.dividerCondition = dividerCondition;
+ }
+
+ /**
+ * Gets whether the divider needs permission from both the item view holder below and above from
+ * where the divider would draw itself or just needs permission from one or the other before
+ * drawing itself.
+ */
+ @DividerCondition
+ public int getDividerCondition() {
+ return dividerCondition;
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/GlifPreferenceLayout.java b/library/recyclerview/src/com/android/setupwizardlib/GlifPreferenceLayout.java
index af1a739..795fdad 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/GlifPreferenceLayout.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/GlifPreferenceLayout.java
@@ -18,21 +18,20 @@ package com.android.setupwizardlib;
import android.content.Context;
import android.os.Bundle;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-
import com.android.setupwizardlib.template.RecyclerMixin;
/**
* A layout to be used with {@code PreferenceFragment} in v14 support library. This can be specified
- * as the {@code android:layout} in the {@code app:preferenceFragmentStyle} in
- * {@code app:preferenceTheme}.
+ * as the {@code android:layout} in the {@code app:preferenceFragmentStyle} in {@code
+ * app:preferenceTheme}.
+ *
+ * <p>Example:
*
- * <p />Example:
* <pre>{@code
* &lt;style android:name="MyActivityTheme">
* &lt;item android:name="preferenceTheme">@style/MyPreferenceTheme&lt;/item>
@@ -47,10 +46,11 @@ import com.android.setupwizardlib.template.RecyclerMixin;
* &lt;/style>
* }</pre>
*
- * where {@code my_preference_layout} is a layout that contains
- * {@link com.android.setupwizardlib.GlifPreferenceLayout}.
+ * where {@code my_preference_layout} is a layout that contains {@link
+ * com.android.setupwizardlib.GlifPreferenceLayout}.
+ *
+ * <p>Example:
*
- * <p />Example:
* <pre>{@code
* &lt;com.android.setupwizardlib.GlifPreferenceLayout
* xmlns:android="http://schemas.android.com/apk/res/android"
@@ -59,60 +59,57 @@ import com.android.setupwizardlib.template.RecyclerMixin;
* android:layout_height="match_parent" />
* }</pre>
*
- * <p />Fragments using this layout <em>must</em> delegate {@code onCreateRecyclerView} to the
- * implementation in this class:
- * {@link #onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup,
- * android.os.Bundle)}
+ * <p>Fragments using this layout <em>must</em> delegate {@code onCreateRecyclerView} to the
+ * implementation in this class: {@link #onCreateRecyclerView(android.view.LayoutInflater,
+ * android.view.ViewGroup, android.os.Bundle)}
*/
public class GlifPreferenceLayout extends GlifRecyclerLayout {
- public GlifPreferenceLayout(Context context) {
- super(context);
- }
+ public GlifPreferenceLayout(Context context) {
+ super(context);
+ }
- public GlifPreferenceLayout(Context context, int template, int containerId) {
- super(context, template, containerId);
- }
+ public GlifPreferenceLayout(Context context, int template, int containerId) {
+ super(context, template, containerId);
+ }
- public GlifPreferenceLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
+ public GlifPreferenceLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
- public GlifPreferenceLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
+ public GlifPreferenceLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
- @Override
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- containerId = R.id.suw_layout_content;
- }
- return super.findContainer(containerId);
+ @Override
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ containerId = R.id.suw_layout_content;
}
+ return super.findContainer(containerId);
+ }
- /**
- * This method must be called in {@code PreferenceFragment#onCreateRecyclerView}.
- */
- public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
- Bundle savedInstanceState) {
- return mRecyclerMixin.getRecyclerView();
- }
+ /** This method must be called in {@code PreferenceFragment#onCreateRecyclerView}. */
+ public RecyclerView onCreateRecyclerView(
+ LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+ return mRecyclerMixin.getRecyclerView();
+ }
- @Override
- protected View onInflateTemplate(LayoutInflater inflater, int template) {
- if (template == 0) {
- template = R.layout.suw_glif_preference_template;
- }
- return super.onInflateTemplate(inflater, template);
+ @Override
+ protected View onInflateTemplate(LayoutInflater inflater, int template) {
+ if (template == 0) {
+ template = R.layout.suw_glif_preference_template;
}
+ return super.onInflateTemplate(inflater, template);
+ }
- @Override
- protected void onTemplateInflated() {
- // Inflate the recycler view here, so attributes on the decoration views can be applied
- // immediately.
- final LayoutInflater inflater = LayoutInflater.from(getContext());
- RecyclerView recyclerView = (RecyclerView) inflater.inflate(
- R.layout.suw_glif_preference_recycler_view, this, false);
- mRecyclerMixin = new RecyclerMixin(this, recyclerView);
- }
+ @Override
+ protected void onTemplateInflated() {
+ // Inflate the recycler view here, so attributes on the decoration views can be applied
+ // immediately.
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ RecyclerView recyclerView =
+ (RecyclerView) inflater.inflate(R.layout.suw_glif_preference_recycler_view, this, false);
+ mRecyclerMixin = new RecyclerMixin(this, recyclerView);
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/GlifRecyclerLayout.java b/library/recyclerview/src/com/android/setupwizardlib/GlifRecyclerLayout.java
index 7e0b1b7..2595b79 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/GlifRecyclerLayout.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/GlifRecyclerLayout.java
@@ -20,15 +20,13 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION_CODES;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-
import com.android.setupwizardlib.template.RecyclerMixin;
import com.android.setupwizardlib.template.RecyclerViewScrollHandlingDelegate;
import com.android.setupwizardlib.template.RequireScrollMixin;
@@ -39,157 +37,137 @@ import com.android.setupwizardlib.template.RequireScrollMixin;
*/
public class GlifRecyclerLayout extends GlifLayout {
- protected RecyclerMixin mRecyclerMixin;
-
- public GlifRecyclerLayout(Context context) {
- this(context, 0, 0);
- }
-
- public GlifRecyclerLayout(Context context, int template) {
- this(context, template, 0);
- }
-
- public GlifRecyclerLayout(Context context, int template, int containerId) {
- super(context, template, containerId);
- init(context, null, 0);
- }
-
- public GlifRecyclerLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs, 0);
- }
-
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public GlifRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs, defStyleAttr);
- }
-
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- mRecyclerMixin.parseAttributes(attrs, defStyleAttr);
- registerMixin(RecyclerMixin.class, mRecyclerMixin);
-
- final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
- requireScrollMixin.setScrollHandlingDelegate(
- new RecyclerViewScrollHandlingDelegate(requireScrollMixin, getRecyclerView()));
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- mRecyclerMixin.onLayout();
- }
-
- @Override
- protected View onInflateTemplate(LayoutInflater inflater, int template) {
- if (template == 0) {
- template = R.layout.suw_glif_recycler_template;
- }
- return super.onInflateTemplate(inflater, template);
- }
-
- @Override
- protected void onTemplateInflated() {
- final View recyclerView = findViewById(R.id.suw_recycler_view);
- if (recyclerView instanceof RecyclerView) {
- mRecyclerMixin = new RecyclerMixin(this, (RecyclerView) recyclerView);
- } else {
- throw new IllegalStateException(
- "GlifRecyclerLayout should use a template with recycler view");
- }
- }
-
- @Override
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- containerId = R.id.suw_recycler_view;
- }
- return super.findContainer(containerId);
- }
-
- @Override
- // Returning generic type is the common pattern used for findViewBy* methods
- @SuppressWarnings("TypeParameterUnusedInFormals")
- public <T extends View> T findManagedViewById(int id) {
- final View header = mRecyclerMixin.getHeader();
- if (header != null) {
- final T view = header.findViewById(id);
- if (view != null) {
- return view;
- }
- }
- return super.findViewById(id);
- }
-
- /**
- * @see RecyclerMixin#setDividerItemDecoration(DividerItemDecoration)
- */
- public void setDividerItemDecoration(DividerItemDecoration decoration) {
- mRecyclerMixin.setDividerItemDecoration(decoration);
- }
-
- /**
- * @see RecyclerMixin#getRecyclerView()
- */
- public RecyclerView getRecyclerView() {
- return mRecyclerMixin.getRecyclerView();
- }
-
- /**
- * @see RecyclerMixin#setAdapter(Adapter)
- */
- public void setAdapter(Adapter<? extends ViewHolder> adapter) {
- mRecyclerMixin.setAdapter(adapter);
- }
-
- /**
- * @see RecyclerMixin#getAdapter()
- */
- public Adapter<? extends ViewHolder> getAdapter() {
- return mRecyclerMixin.getAdapter();
- }
-
- /**
- * @deprecated Use {@link #setDividerInsets(int, int)} instead.
- */
- @Deprecated
- public void setDividerInset(int inset) {
- mRecyclerMixin.setDividerInset(inset);
- }
-
- /**
- * @see RecyclerMixin#setDividerInset(int)
- */
- public void setDividerInsets(int start, int end) {
- mRecyclerMixin.setDividerInsets(start, end);
- }
-
- /**
- * @deprecated Use {@link #getDividerInsetStart()} instead.
- */
- @Deprecated
- public int getDividerInset() {
- return mRecyclerMixin.getDividerInset();
- }
-
- /**
- * @see RecyclerMixin#getDividerInsetStart()
- */
- public int getDividerInsetStart() {
- return mRecyclerMixin.getDividerInsetStart();
- }
-
- /**
- * @see RecyclerMixin#getDividerInsetEnd()
- */
- public int getDividerInsetEnd() {
- return mRecyclerMixin.getDividerInsetEnd();
- }
-
- /**
- * @see RecyclerMixin#getDivider()
- */
- public Drawable getDivider() {
- return mRecyclerMixin.getDivider();
- }
+ protected RecyclerMixin mRecyclerMixin;
+
+ public GlifRecyclerLayout(Context context) {
+ this(context, 0, 0);
+ }
+
+ public GlifRecyclerLayout(Context context, int template) {
+ this(context, template, 0);
+ }
+
+ public GlifRecyclerLayout(Context context, int template, int containerId) {
+ super(context, template, containerId);
+ init(null, 0);
+ }
+
+ public GlifRecyclerLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ public GlifRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ mRecyclerMixin.parseAttributes(attrs, defStyleAttr);
+ registerMixin(RecyclerMixin.class, mRecyclerMixin);
+
+ final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
+ requireScrollMixin.setScrollHandlingDelegate(
+ new RecyclerViewScrollHandlingDelegate(requireScrollMixin, getRecyclerView()));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ mRecyclerMixin.onLayout();
+ }
+
+ @Override
+ protected View onInflateTemplate(LayoutInflater inflater, int template) {
+ if (template == 0) {
+ template = R.layout.suw_glif_recycler_template;
+ }
+ return super.onInflateTemplate(inflater, template);
+ }
+
+ @Override
+ protected void onTemplateInflated() {
+ final View recyclerView = findViewById(R.id.suw_recycler_view);
+ if (recyclerView instanceof RecyclerView) {
+ mRecyclerMixin = new RecyclerMixin(this, (RecyclerView) recyclerView);
+ } else {
+ throw new IllegalStateException(
+ "GlifRecyclerLayout should use a template with recycler view");
+ }
+ }
+
+ @Override
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ containerId = R.id.suw_recycler_view;
+ }
+ return super.findContainer(containerId);
+ }
+
+ @Override
+ // Returning generic type is the common pattern used for findViewBy* methods
+ @SuppressWarnings("TypeParameterUnusedInFormals")
+ public <T extends View> T findManagedViewById(int id) {
+ final View header = mRecyclerMixin.getHeader();
+ if (header != null) {
+ final T view = header.findViewById(id);
+ if (view != null) {
+ return view;
+ }
+ }
+ return super.findViewById(id);
+ }
+
+ /** @see RecyclerMixin#setDividerItemDecoration(DividerItemDecoration) */
+ public void setDividerItemDecoration(DividerItemDecoration decoration) {
+ mRecyclerMixin.setDividerItemDecoration(decoration);
+ }
+
+ /** @see RecyclerMixin#getRecyclerView() */
+ public RecyclerView getRecyclerView() {
+ return mRecyclerMixin.getRecyclerView();
+ }
+
+ /** @see RecyclerMixin#setAdapter(Adapter) */
+ public void setAdapter(Adapter<? extends ViewHolder> adapter) {
+ mRecyclerMixin.setAdapter(adapter);
+ }
+
+ /** @see RecyclerMixin#getAdapter() */
+ public Adapter<? extends ViewHolder> getAdapter() {
+ return mRecyclerMixin.getAdapter();
+ }
+
+ /** @deprecated Use {@link #setDividerInsets(int, int)} instead. */
+ @Deprecated
+ public void setDividerInset(int inset) {
+ mRecyclerMixin.setDividerInset(inset);
+ }
+
+ /** @see RecyclerMixin#setDividerInset(int) */
+ public void setDividerInsets(int start, int end) {
+ mRecyclerMixin.setDividerInsets(start, end);
+ }
+
+ /** @deprecated Use {@link #getDividerInsetStart()} instead. */
+ @Deprecated
+ public int getDividerInset() {
+ return mRecyclerMixin.getDividerInset();
+ }
+
+ /** @see RecyclerMixin#getDividerInsetStart() */
+ public int getDividerInsetStart() {
+ return mRecyclerMixin.getDividerInsetStart();
+ }
+
+ /** @see RecyclerMixin#getDividerInsetEnd() */
+ public int getDividerInsetEnd() {
+ return mRecyclerMixin.getDividerInsetEnd();
+ }
+
+ /** @see RecyclerMixin#getDivider() */
+ public Drawable getDivider() {
+ return mRecyclerMixin.getDivider();
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/SetupWizardPreferenceLayout.java b/library/recyclerview/src/com/android/setupwizardlib/SetupWizardPreferenceLayout.java
index 670c309..e9aa329 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/SetupWizardPreferenceLayout.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/SetupWizardPreferenceLayout.java
@@ -18,21 +18,20 @@ package com.android.setupwizardlib;
import android.content.Context;
import android.os.Bundle;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-
import com.android.setupwizardlib.template.RecyclerMixin;
/**
* A layout to be used with {@code PreferenceFragment} in v14 support library. This can be specified
- * as the {@code android:layout} in the {@code app:preferenceFragmentStyle} in
- * {@code app:preferenceTheme}.
+ * as the {@code android:layout} in the {@code app:preferenceFragmentStyle} in {@code
+ * app:preferenceTheme}.
+ *
+ * <p>Example:
*
- * <p />Example:
* <pre>{@code
* &lt;style android:name="MyActivityTheme">
* &lt;item android:name="preferenceTheme">@style/MyPreferenceTheme&lt;/item>
@@ -47,10 +46,11 @@ import com.android.setupwizardlib.template.RecyclerMixin;
* &lt;/style>
* }</pre>
*
- * where {@code my_preference_layout} is a layout that contains
- * {@link com.android.setupwizardlib.SetupWizardPreferenceLayout}.
+ * where {@code my_preference_layout} is a layout that contains {@link
+ * com.android.setupwizardlib.SetupWizardPreferenceLayout}.
+ *
+ * <p>Example:
*
- * <p />Example:
* <pre>{@code
* &lt;com.android.setupwizardlib.SetupWizardPreferenceLayout
* xmlns:android="http://schemas.android.com/apk/res/android"
@@ -59,58 +59,56 @@ import com.android.setupwizardlib.template.RecyclerMixin;
* android:layout_height="match_parent" />
* }</pre>
*
- * <p />Fragments using this layout <em>must</em> delegate {@code onCreateRecyclerView} to the
+ * <p>Fragments using this layout <em>must</em> delegate {@code onCreateRecyclerView} to the
* implementation in this class: {@link #onCreateRecyclerView}
*/
public class SetupWizardPreferenceLayout extends SetupWizardRecyclerLayout {
- public SetupWizardPreferenceLayout(Context context) {
- super(context);
- }
+ public SetupWizardPreferenceLayout(Context context) {
+ super(context);
+ }
- public SetupWizardPreferenceLayout(Context context, int template, int containerId) {
- super(context, template, containerId);
- }
+ public SetupWizardPreferenceLayout(Context context, int template, int containerId) {
+ super(context, template, containerId);
+ }
- public SetupWizardPreferenceLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
+ public SetupWizardPreferenceLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
- public SetupWizardPreferenceLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
+ public SetupWizardPreferenceLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
- @Override
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- containerId = R.id.suw_layout_content;
- }
- return super.findContainer(containerId);
+ @Override
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ containerId = R.id.suw_layout_content;
}
+ return super.findContainer(containerId);
+ }
- /**
- * This method must be called in {@code PreferenceFragment#onCreateRecyclerView}.
- */
- public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
- Bundle savedInstanceState) {
- return mRecyclerMixin.getRecyclerView();
- }
+ /** This method must be called in {@code PreferenceFragment#onCreateRecyclerView}. */
+ public RecyclerView onCreateRecyclerView(
+ LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+ return mRecyclerMixin.getRecyclerView();
+ }
- @Override
- protected View onInflateTemplate(LayoutInflater inflater, int template) {
- if (template == 0) {
- template = R.layout.suw_preference_template;
- }
- return super.onInflateTemplate(inflater, template);
+ @Override
+ protected View onInflateTemplate(LayoutInflater inflater, int template) {
+ if (template == 0) {
+ template = R.layout.suw_preference_template;
}
+ return super.onInflateTemplate(inflater, template);
+ }
- @Override
- protected void onTemplateInflated() {
- // Inflate the recycler view here, so attributes on the decoration views can be applied
- // immediately.
- final LayoutInflater inflater = LayoutInflater.from(getContext());
- RecyclerView recyclerView = (RecyclerView) inflater.inflate(
- R.layout.suw_preference_recycler_view, this, false);
- mRecyclerMixin = new RecyclerMixin(this, recyclerView);
- }
+ @Override
+ protected void onTemplateInflated() {
+ // Inflate the recycler view here, so attributes on the decoration views can be applied
+ // immediately.
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ RecyclerView recyclerView =
+ (RecyclerView) inflater.inflate(R.layout.suw_preference_recycler_view, this, false);
+ mRecyclerMixin = new RecyclerMixin(this, recyclerView);
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/SetupWizardRecyclerLayout.java b/library/recyclerview/src/com/android/setupwizardlib/SetupWizardRecyclerLayout.java
index 5d3f1a5..ba0b598 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/SetupWizardRecyclerLayout.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/SetupWizardRecyclerLayout.java
@@ -18,178 +18,156 @@ package com.android.setupwizardlib;
import android.content.Context;
import android.graphics.drawable.Drawable;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-
import com.android.setupwizardlib.template.RecyclerMixin;
import com.android.setupwizardlib.template.RecyclerViewScrollHandlingDelegate;
import com.android.setupwizardlib.template.RequireScrollMixin;
/**
- * A setup wizard layout for use with {@link androidx.recyclerview.widget.RecyclerView}.
- * {@code android:entries} can also be used to specify an
- * {@link com.android.setupwizardlib.items.ItemHierarchy} to be used with this layout in XML.
+ * A setup wizard layout for use with {@link androidx.recyclerview.widget.RecyclerView}. {@code
+ * android:entries} can also be used to specify an {@link
+ * com.android.setupwizardlib.items.ItemHierarchy} to be used with this layout in XML.
*
* @see SetupWizardListLayout
*/
public class SetupWizardRecyclerLayout extends SetupWizardLayout {
- private static final String TAG = "RecyclerLayout";
-
- protected RecyclerMixin mRecyclerMixin;
-
- public SetupWizardRecyclerLayout(Context context) {
- this(context, 0, 0);
- }
-
- public SetupWizardRecyclerLayout(Context context, int template, int containerId) {
- super(context, template, containerId);
- init(context, null, 0);
- }
-
- public SetupWizardRecyclerLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context, attrs, 0);
- }
-
- public SetupWizardRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(context, attrs, defStyleAttr);
- }
-
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- mRecyclerMixin.parseAttributes(attrs, defStyleAttr);
- registerMixin(RecyclerMixin.class, mRecyclerMixin);
-
-
- final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
- requireScrollMixin.setScrollHandlingDelegate(
- new RecyclerViewScrollHandlingDelegate(requireScrollMixin, getRecyclerView()));
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- mRecyclerMixin.onLayout();
- }
-
- /**
- * @see RecyclerMixin#getAdapter()
- */
- public Adapter<? extends ViewHolder> getAdapter() {
- return mRecyclerMixin.getAdapter();
- }
-
- /**
- * @see RecyclerMixin#setAdapter(Adapter)
- */
- public void setAdapter(Adapter<? extends ViewHolder> adapter) {
- mRecyclerMixin.setAdapter(adapter);
- }
-
- /**
- * @see RecyclerMixin#getRecyclerView()
- */
- public RecyclerView getRecyclerView() {
- return mRecyclerMixin.getRecyclerView();
- }
-
- @Override
- protected ViewGroup findContainer(int containerId) {
- if (containerId == 0) {
- containerId = R.id.suw_recycler_view;
- }
- return super.findContainer(containerId);
- }
-
- @Override
- protected View onInflateTemplate(LayoutInflater inflater, int template) {
- if (template == 0) {
- template = R.layout.suw_recycler_template;
- }
- return super.onInflateTemplate(inflater, template);
- }
-
- @Override
- protected void onTemplateInflated() {
- final View recyclerView = findViewById(R.id.suw_recycler_view);
- if (recyclerView instanceof RecyclerView) {
- mRecyclerMixin = new RecyclerMixin(this, (RecyclerView) recyclerView);
- } else {
- throw new IllegalStateException(
- "SetupWizardRecyclerLayout should use a template with recycler view");
- }
- }
-
- @Override
- // Returning generic type is the common pattern used for findViewBy* methods
- @SuppressWarnings("TypeParameterUnusedInFormals")
- public <T extends View> T findManagedViewById(int id) {
- final View header = mRecyclerMixin.getHeader();
- if (header != null) {
- final T view = header.findViewById(id);
- if (view != null) {
- return view;
- }
- }
- return super.findViewById(id);
- }
-
- /**
- * @deprecated Use {@link #setDividerInsets(int, int)} instead.
- */
- @Deprecated
- public void setDividerInset(int inset) {
- mRecyclerMixin.setDividerInset(inset);
- }
-
- /**
- * Sets the start inset of the divider. This will use the default divider drawable set in the
- * theme and apply insets to it.
- *
- * @param start The number of pixels to inset on the "start" side of the list divider. Typically
- * this will be either {@code @dimen/suw_items_icon_divider_inset} or
- * {@code @dimen/suw_items_text_divider_inset}.
- * @param end The number of pixels to inset on the "end" side of the list divider.
- *
- * @see RecyclerMixin#setDividerInsets(int, int)
- */
- public void setDividerInsets(int start, int end) {
- mRecyclerMixin.setDividerInsets(start, end);
- }
-
- /**
- * @deprecated Use {@link #getDividerInsetStart()} instead.
- */
- @Deprecated
- public int getDividerInset() {
- return mRecyclerMixin.getDividerInset();
- }
-
- /**
- * @see RecyclerMixin#getDividerInsetStart()
- */
- public int getDividerInsetStart() {
- return mRecyclerMixin.getDividerInsetStart();
- }
-
- /**
- * @see RecyclerMixin#getDividerInsetEnd()
- */
- public int getDividerInsetEnd() {
- return mRecyclerMixin.getDividerInsetEnd();
- }
-
- /**
- * @see RecyclerMixin#getDivider()
- */
- public Drawable getDivider() {
- return mRecyclerMixin.getDivider();
- }
+ protected RecyclerMixin mRecyclerMixin;
+
+ public SetupWizardRecyclerLayout(Context context) {
+ this(context, 0, 0);
+ }
+
+ public SetupWizardRecyclerLayout(Context context, int template, int containerId) {
+ super(context, template, containerId);
+ init(null, 0);
+ }
+
+ public SetupWizardRecyclerLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ public SetupWizardRecyclerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ mRecyclerMixin.parseAttributes(attrs, defStyleAttr);
+ registerMixin(RecyclerMixin.class, mRecyclerMixin);
+
+ final RequireScrollMixin requireScrollMixin = getMixin(RequireScrollMixin.class);
+ requireScrollMixin.setScrollHandlingDelegate(
+ new RecyclerViewScrollHandlingDelegate(requireScrollMixin, getRecyclerView()));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ mRecyclerMixin.onLayout();
+ }
+
+ /** @see RecyclerMixin#getAdapter() */
+ public Adapter<? extends ViewHolder> getAdapter() {
+ return mRecyclerMixin.getAdapter();
+ }
+
+ /** @see RecyclerMixin#setAdapter(Adapter) */
+ public void setAdapter(Adapter<? extends ViewHolder> adapter) {
+ mRecyclerMixin.setAdapter(adapter);
+ }
+
+ /** @see RecyclerMixin#getRecyclerView() */
+ public RecyclerView getRecyclerView() {
+ return mRecyclerMixin.getRecyclerView();
+ }
+
+ @Override
+ protected ViewGroup findContainer(int containerId) {
+ if (containerId == 0) {
+ containerId = R.id.suw_recycler_view;
+ }
+ return super.findContainer(containerId);
+ }
+
+ @Override
+ protected View onInflateTemplate(LayoutInflater inflater, int template) {
+ if (template == 0) {
+ template = R.layout.suw_recycler_template;
+ }
+ return super.onInflateTemplate(inflater, template);
+ }
+
+ @Override
+ protected void onTemplateInflated() {
+ final View recyclerView = findViewById(R.id.suw_recycler_view);
+ if (recyclerView instanceof RecyclerView) {
+ mRecyclerMixin = new RecyclerMixin(this, (RecyclerView) recyclerView);
+ } else {
+ throw new IllegalStateException(
+ "SetupWizardRecyclerLayout should use a template with recycler view");
+ }
+ }
+
+ @Override
+ // Returning generic type is the common pattern used for findViewBy* methods
+ @SuppressWarnings("TypeParameterUnusedInFormals")
+ public <T extends View> T findManagedViewById(int id) {
+ final View header = mRecyclerMixin.getHeader();
+ if (header != null) {
+ final T view = header.findViewById(id);
+ if (view != null) {
+ return view;
+ }
+ }
+ return super.findViewById(id);
+ }
+
+ /** @deprecated Use {@link #setDividerInsets(int, int)} instead. */
+ @Deprecated
+ public void setDividerInset(int inset) {
+ mRecyclerMixin.setDividerInset(inset);
+ }
+
+ /**
+ * Sets the start inset of the divider. This will use the default divider drawable set in the
+ * theme and apply insets to it.
+ *
+ * @param start The number of pixels to inset on the "start" side of the list divider. Typically
+ * this will be either {@code @dimen/suw_items_icon_divider_inset} or
+ * {@code @dimen/suw_items_text_divider_inset}.
+ * @param end The number of pixels to inset on the "end" side of the list divider.
+ * @see RecyclerMixin#setDividerInsets(int, int)
+ */
+ public void setDividerInsets(int start, int end) {
+ mRecyclerMixin.setDividerInsets(start, end);
+ }
+
+ /** @deprecated Use {@link #getDividerInsetStart()} instead. */
+ @Deprecated
+ public int getDividerInset() {
+ return mRecyclerMixin.getDividerInset();
+ }
+
+ /** @see RecyclerMixin#getDividerInsetStart() */
+ public int getDividerInsetStart() {
+ return mRecyclerMixin.getDividerInsetStart();
+ }
+
+ /** @see RecyclerMixin#getDividerInsetEnd() */
+ public int getDividerInsetEnd() {
+ return mRecyclerMixin.getDividerInsetEnd();
+ }
+
+ /** @see RecyclerMixin#getDivider() */
+ public Drawable getDivider() {
+ return mRecyclerMixin.getDivider();
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/items/ItemViewHolder.java b/library/recyclerview/src/com/android/setupwizardlib/items/ItemViewHolder.java
index aeaba68..419e2aa 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/items/ItemViewHolder.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/items/ItemViewHolder.java
@@ -16,44 +16,42 @@
package com.android.setupwizardlib.items;
-import android.view.View;
-
import androidx.recyclerview.widget.RecyclerView;
-
+import android.view.View;
import com.android.setupwizardlib.DividerItemDecoration;
class ItemViewHolder extends RecyclerView.ViewHolder
- implements DividerItemDecoration.DividedViewHolder {
-
- private boolean mIsEnabled;
- private IItem mItem;
-
- ItemViewHolder(View itemView) {
- super(itemView);
- }
-
- @Override
- public boolean isDividerAllowedAbove() {
- return mIsEnabled;
- }
-
- @Override
- public boolean isDividerAllowedBelow() {
- return mIsEnabled;
- }
-
- public void setEnabled(boolean isEnabled) {
- mIsEnabled = isEnabled;
- itemView.setClickable(isEnabled);
- itemView.setEnabled(isEnabled);
- itemView.setFocusable(isEnabled);
- }
-
- public void setItem(IItem item) {
- mItem = item;
- }
-
- public IItem getItem() {
- return mItem;
- }
+ implements DividerItemDecoration.DividedViewHolder {
+
+ private boolean isEnabled;
+ private IItem item;
+
+ ItemViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ @Override
+ public boolean isDividerAllowedAbove() {
+ return isEnabled;
+ }
+
+ @Override
+ public boolean isDividerAllowedBelow() {
+ return isEnabled;
+ }
+
+ public void setEnabled(boolean isEnabled) {
+ this.isEnabled = isEnabled;
+ itemView.setClickable(isEnabled);
+ itemView.setEnabled(isEnabled);
+ itemView.setFocusable(isEnabled);
+ }
+
+ public void setItem(IItem item) {
+ this.item = item;
+ }
+
+ public IItem getItem() {
+ return item;
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/items/RecyclerItemAdapter.java b/library/recyclerview/src/com/android/setupwizardlib/items/RecyclerItemAdapter.java
index 56c60e7..ee753b8 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/items/RecyclerItemAdapter.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/items/RecyclerItemAdapter.java
@@ -20,14 +20,12 @@ import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
+import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.recyclerview.widget.RecyclerView;
-
import com.android.setupwizardlib.R;
/**
@@ -36,217 +34,214 @@ import com.android.setupwizardlib.R;
* XML.
*/
public class RecyclerItemAdapter extends RecyclerView.Adapter<ItemViewHolder>
- implements ItemHierarchy.Observer {
+ implements ItemHierarchy.Observer {
- private static final String TAG = "RecyclerItemAdapter";
+ private static final String TAG = "RecyclerItemAdapter";
- /**
- * A view tag set by {@link View#setTag(Object)}. If set on the root view of a layout, it will
- * not create the default background for the list item. This means the item will not have ripple
- * touch feedback by default.
- */
- public static final String TAG_NO_BACKGROUND = "noBackground";
+ /**
+ * A view tag set by {@link View#setTag(Object)}. If set on the root view of a layout, it will not
+ * create the default background for the list item. This means the item will not have ripple touch
+ * feedback by default.
+ */
+ public static final String TAG_NO_BACKGROUND = "noBackground";
- /**
- * Listener for item selection in this adapter.
- */
- public interface OnItemSelectedListener {
-
- /**
- * Called when an item in this adapter is clicked.
- *
- * @param item The Item corresponding to the position being clicked.
- */
- void onItemSelected(IItem item);
- }
-
- private final ItemHierarchy mItemHierarchy;
- private OnItemSelectedListener mListener;
-
- public RecyclerItemAdapter(ItemHierarchy hierarchy) {
- mItemHierarchy = hierarchy;
- mItemHierarchy.registerObserver(this);
- }
+ /** Listener for item selection in this adapter. */
+ public interface OnItemSelectedListener {
/**
- * Gets the item at the given position.
+ * Called when an item in this adapter is clicked.
*
- * @see ItemHierarchy#getItemAt(int)
+ * @param item The Item corresponding to the position being clicked.
*/
- public IItem getItem(int position) {
- return mItemHierarchy.getItemAt(position);
- }
-
- @Override
- public long getItemId(int position) {
- IItem mItem = getItem(position);
- if (mItem instanceof AbstractItem) {
- final int id = ((AbstractItem) mItem).getId();
- return id > 0 ? id : RecyclerView.NO_ID;
- } else {
- return RecyclerView.NO_ID;
- }
- }
-
- @Override
- public int getItemCount() {
- return mItemHierarchy.getCount();
- }
-
- @Override
- public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
- final View view = inflater.inflate(viewType, parent, false);
- final ItemViewHolder viewHolder = new ItemViewHolder(view);
-
- final Object viewTag = view.getTag();
- if (!TAG_NO_BACKGROUND.equals(viewTag)) {
- final TypedArray typedArray = parent.getContext()
- .obtainStyledAttributes(R.styleable.SuwRecyclerItemAdapter);
- Drawable selectableItemBackground = typedArray.getDrawable(
- R.styleable.SuwRecyclerItemAdapter_android_selectableItemBackground);
- if (selectableItemBackground == null) {
- selectableItemBackground = typedArray.getDrawable(
- R.styleable.SuwRecyclerItemAdapter_selectableItemBackground);
- }
-
- Drawable background = view.getBackground();
- if (background == null) {
- background = typedArray.getDrawable(
- R.styleable.SuwRecyclerItemAdapter_android_colorBackground);
- }
-
- if (selectableItemBackground == null || background == null) {
- Log.e(TAG, "Cannot resolve required attributes."
- + " selectableItemBackground=" + selectableItemBackground
- + " background=" + background);
- } else {
- final Drawable[] layers = {background, selectableItemBackground};
- view.setBackgroundDrawable(new PatchedLayerDrawable(layers));
- }
-
- typedArray.recycle();
- }
-
- view.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- final IItem item = viewHolder.getItem();
- if (mListener != null && item != null && item.isEnabled()) {
- mListener.onItemSelected(item);
- }
+ void onItemSelected(IItem item);
+ }
+
+ private final ItemHierarchy itemHierarchy;
+ private OnItemSelectedListener listener;
+
+ public RecyclerItemAdapter(ItemHierarchy hierarchy) {
+ itemHierarchy = hierarchy;
+ itemHierarchy.registerObserver(this);
+ }
+
+ /**
+ * Gets the item at the given position.
+ *
+ * @see ItemHierarchy#getItemAt(int)
+ */
+ public IItem getItem(int position) {
+ return itemHierarchy.getItemAt(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ IItem mItem = getItem(position);
+ if (mItem instanceof AbstractItem) {
+ final int id = ((AbstractItem) mItem).getId();
+ return id > 0 ? id : RecyclerView.NO_ID;
+ } else {
+ return RecyclerView.NO_ID;
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return itemHierarchy.getCount();
+ }
+
+ @Override
+ public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ final View view = inflater.inflate(viewType, parent, false);
+ final ItemViewHolder viewHolder = new ItemViewHolder(view);
+
+ final Object viewTag = view.getTag();
+ if (!TAG_NO_BACKGROUND.equals(viewTag)) {
+ final TypedArray typedArray =
+ parent.getContext().obtainStyledAttributes(R.styleable.SuwRecyclerItemAdapter);
+ Drawable selectableItemBackground =
+ typedArray.getDrawable(
+ R.styleable.SuwRecyclerItemAdapter_android_selectableItemBackground);
+ if (selectableItemBackground == null) {
+ selectableItemBackground =
+ typedArray.getDrawable(R.styleable.SuwRecyclerItemAdapter_selectableItemBackground);
+ }
+
+ Drawable background = view.getBackground();
+ if (background == null) {
+ background =
+ typedArray.getDrawable(R.styleable.SuwRecyclerItemAdapter_android_colorBackground);
+ }
+
+ if (selectableItemBackground == null || background == null) {
+ Log.e(
+ TAG,
+ "Cannot resolve required attributes."
+ + " selectableItemBackground="
+ + selectableItemBackground
+ + " background="
+ + background);
+ } else {
+ final Drawable[] layers = {background, selectableItemBackground};
+ view.setBackgroundDrawable(new PatchedLayerDrawable(layers));
+ }
+
+ typedArray.recycle();
+ }
+
+ view.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ final IItem item = viewHolder.getItem();
+ if (listener != null && item != null && item.isEnabled()) {
+ listener.onItemSelected(item);
}
+ }
});
- return viewHolder;
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(ItemViewHolder holder, int position) {
+ final IItem item = getItem(position);
+ holder.setEnabled(item.isEnabled());
+ holder.setItem(item);
+ item.onBindView(holder.itemView);
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ // Use layout resource as item view type. RecyclerView item type does not have to be
+ // contiguous.
+ IItem item = getItem(position);
+ return item.getLayoutResource();
+ }
+
+ @Override
+ public void onChanged(ItemHierarchy hierarchy) {
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onItemRangeChanged(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ notifyItemRangeChanged(positionStart, itemCount);
+ }
+
+ @Override
+ public void onItemRangeInserted(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ notifyItemRangeInserted(positionStart, itemCount);
+ }
+
+ @Override
+ public void onItemRangeMoved(
+ ItemHierarchy itemHierarchy, int fromPosition, int toPosition, int itemCount) {
+ // There is no notifyItemRangeMoved
+ // https://code.google.com/p/android/issues/detail?id=125984
+ if (itemCount == 1) {
+ notifyItemMoved(fromPosition, toPosition);
+ } else {
+ // If more than one, degenerate into the catch-all data set changed callback, since I'm
+ // not sure how recycler view handles multiple calls to notifyItemMoved (if the result
+ // is committed after every notification then naively calling
+ // notifyItemMoved(from + i, to + i) is wrong).
+ // Logging this in case this is a more common occurrence than expected.
+ Log.i(TAG, "onItemRangeMoved with more than one item");
+ notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onItemRangeRemoved(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
+ notifyItemRangeRemoved(positionStart, itemCount);
+ }
+
+ /**
+ * Find an item hierarchy within the root hierarchy.
+ *
+ * @see ItemHierarchy#findItemById(int)
+ */
+ public ItemHierarchy findItemById(int id) {
+ return itemHierarchy.findItemById(id);
+ }
+
+ /** Gets the root item hierarchy in this adapter. */
+ public ItemHierarchy getRootItemHierarchy() {
+ return itemHierarchy;
+ }
+
+ /**
+ * Sets the listener to listen for when user clicks on a item.
+ *
+ * @see OnItemSelectedListener
+ */
+ public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+ this.listener = listener;
+ }
+
+ /**
+ * Before Lollipop, LayerDrawable always return true in getPadding, even if the children layers do
+ * not have any padding. Patch the implementation so that getPadding returns false if the padding
+ * is empty.
+ *
+ * <p>When getPadding is true, the padding of the view will be replaced by the padding of the
+ * drawable when {@link View#setBackgroundDrawable(Drawable)} is called. This patched class makes
+ * sure layer drawables without padding does not clear out original padding on the view.
+ */
+ @VisibleForTesting
+ static class PatchedLayerDrawable extends LayerDrawable {
+
+ /** {@inheritDoc} */
+ PatchedLayerDrawable(Drawable[] layers) {
+ super(layers);
}
@Override
- public void onBindViewHolder(ItemViewHolder holder, int position) {
- final IItem item = getItem(position);
- holder.setEnabled(item.isEnabled());
- holder.setItem(item);
- item.onBindView(holder.itemView);
- }
-
- @Override
- public int getItemViewType(int position) {
- // Use layout resource as item view type. RecyclerView item type does not have to be
- // contiguous.
- IItem item = getItem(position);
- return item.getLayoutResource();
- }
-
- @Override
- public void onChanged(ItemHierarchy hierarchy) {
- notifyDataSetChanged();
- }
-
- @Override
- public void onItemRangeChanged(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- notifyItemRangeChanged(positionStart, itemCount);
- }
-
- @Override
- public void onItemRangeInserted(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- notifyItemRangeInserted(positionStart, itemCount);
- }
-
- @Override
- public void onItemRangeMoved(ItemHierarchy itemHierarchy, int fromPosition, int toPosition,
- int itemCount) {
- // There is no notifyItemRangeMoved
- // https://code.google.com/p/android/issues/detail?id=125984
- if (itemCount == 1) {
- notifyItemMoved(fromPosition, toPosition);
- } else {
- // If more than one, degenerate into the catch-all data set changed callback, since I'm
- // not sure how recycler view handles multiple calls to notifyItemMoved (if the result
- // is committed after every notification then naively calling
- // notifyItemMoved(from + i, to + i) is wrong).
- // Logging this in case this is a more common occurrence than expected.
- Log.i(TAG, "onItemRangeMoved with more than one item");
- notifyDataSetChanged();
- }
- }
-
- @Override
- public void onItemRangeRemoved(ItemHierarchy itemHierarchy, int positionStart, int itemCount) {
- notifyItemRangeRemoved(positionStart, itemCount);
- }
-
- /**
- * Find an item hierarchy within the root hierarchy.
- *
- * @see ItemHierarchy#findItemById(int)
- */
- public ItemHierarchy findItemById(int id) {
- return mItemHierarchy.findItemById(id);
- }
-
- /**
- * Gets the root item hierarchy in this adapter.
- */
- public ItemHierarchy getRootItemHierarchy() {
- return mItemHierarchy;
- }
-
- /**
- * Sets the listener to listen for when user clicks on a item.
- *
- * @see OnItemSelectedListener
- */
- public void setOnItemSelectedListener(OnItemSelectedListener listener) {
- mListener = listener;
- }
-
- /**
- * Before Lollipop, LayerDrawable always return true in getPadding, even if the children layers
- * do not have any padding. Patch the implementation so that getPadding returns false if the
- * padding is empty.
- *
- * When getPadding is true, the padding of the view will be replaced by the padding of the
- * drawable when {@link View#setBackgroundDrawable(Drawable)} is called. This patched class
- * makes sure layer drawables without padding does not clear out original padding on the view.
- */
- @VisibleForTesting
- static class PatchedLayerDrawable extends LayerDrawable {
-
- /**
- * {@inheritDoc}
- */
- PatchedLayerDrawable(Drawable[] layers) {
- super(layers);
- }
-
- @Override
- public boolean getPadding(Rect padding) {
- final boolean superHasPadding = super.getPadding(padding);
- return superHasPadding
- && !(padding.left == 0
- && padding.top == 0
- && padding.right == 0
- && padding.bottom == 0);
- }
+ public boolean getPadding(Rect padding) {
+ final boolean superHasPadding = super.getPadding(padding);
+ return superHasPadding
+ && !(padding.left == 0 && padding.top == 0 && padding.right == 0 && padding.bottom == 0);
}
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/template/RecyclerMixin.java b/library/recyclerview/src/com/android/setupwizardlib/template/RecyclerMixin.java
index 32e7bd8..a6c6526 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/template/RecyclerMixin.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/template/RecyclerMixin.java
@@ -21,16 +21,14 @@ import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Build.VERSION_CODES;
-import android.util.AttributeSet;
-import android.view.View;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-
+import android.util.AttributeSet;
+import android.view.View;
import com.android.setupwizardlib.DividerItemDecoration;
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.TemplateLayout;
@@ -51,223 +49,208 @@ import com.android.setupwizardlib.view.HeaderRecyclerView.HeaderAdapter;
*/
public class RecyclerMixin implements Mixin {
- private TemplateLayout mTemplateLayout;
+ private final TemplateLayout templateLayout;
- @NonNull
- private final RecyclerView mRecyclerView;
+ @NonNull private final RecyclerView recyclerView;
- @Nullable
- private View mHeader;
+ @Nullable private View header;
- @NonNull
- private DividerItemDecoration mDividerDecoration;
+ @NonNull private DividerItemDecoration dividerDecoration;
- private Drawable mDefaultDivider;
- private Drawable mDivider;
+ private Drawable defaultDivider;
+ private Drawable divider;
- private int mDividerInsetStart;
- private int mDividerInsetEnd;
+ private int dividerInsetStart;
+ private int dividerInsetEnd;
- /**
- * Creates the RecyclerMixin. Unlike typical mixins which are created in the constructor, this
- * mixin should be called in {@link TemplateLayout#onTemplateInflated()}, which is called by
- * the super constructor, because the recycler view and the header needs to be made available
- * before other mixins from the super class.
- *
- * @param layout The layout this mixin belongs to.
- */
- public RecyclerMixin(@NonNull TemplateLayout layout, @NonNull RecyclerView recyclerView) {
- mTemplateLayout = layout;
+ /**
+ * Creates the RecyclerMixin. Unlike typical mixins which are created in the constructor, this
+ * mixin should be called in {@link TemplateLayout#onTemplateInflated()}, which is called by the
+ * super constructor, because the recycler view and the header needs to be made available before
+ * other mixins from the super class.
+ *
+ * @param layout The layout this mixin belongs to.
+ */
+ public RecyclerMixin(@NonNull TemplateLayout layout, @NonNull RecyclerView recyclerView) {
+ templateLayout = layout;
- mDividerDecoration = new DividerItemDecoration(mTemplateLayout.getContext());
+ dividerDecoration = new DividerItemDecoration(templateLayout.getContext());
- // The recycler view needs to be available
- mRecyclerView = recyclerView;
- mRecyclerView.setLayoutManager(new LinearLayoutManager(mTemplateLayout.getContext()));
+ // The recycler view needs to be available
+ this.recyclerView = recyclerView;
+ this.recyclerView.setLayoutManager(new LinearLayoutManager(templateLayout.getContext()));
- if (recyclerView instanceof HeaderRecyclerView) {
- mHeader = ((HeaderRecyclerView) recyclerView).getHeader();
- }
-
- mRecyclerView.addItemDecoration(mDividerDecoration);
+ if (recyclerView instanceof HeaderRecyclerView) {
+ header = ((HeaderRecyclerView) recyclerView).getHeader();
}
- /**
- * Parse XML attributes and configures this mixin and the recycler view accordingly. This should
- * be called from the constructor of the layout.
- *
- * @param attrs The {@link AttributeSet} as passed into the constructor. Can be null if the
- * layout was not created from XML.
- * @param defStyleAttr The default style attribute as passed into the layout constructor. Can be
- * 0 if it is not needed.
- */
- public void parseAttributes(@Nullable AttributeSet attrs, int defStyleAttr) {
- final Context context = mTemplateLayout.getContext();
- final TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.SuwRecyclerMixin, defStyleAttr, 0);
-
- final int entries = a.getResourceId(R.styleable.SuwRecyclerMixin_android_entries, 0);
- if (entries != 0) {
- final ItemHierarchy inflated = new ItemInflater(context).inflate(entries);
- final RecyclerItemAdapter adapter = new RecyclerItemAdapter(inflated);
- adapter.setHasStableIds(a.getBoolean(
- R.styleable.SuwRecyclerMixin_suwHasStableIds, false));
- setAdapter(adapter);
- }
- int dividerInset =
- a.getDimensionPixelSize(R.styleable.SuwRecyclerMixin_suwDividerInset, -1);
- if (dividerInset != -1) {
- setDividerInset(dividerInset);
- } else {
- int dividerInsetStart =
- a.getDimensionPixelSize(R.styleable.SuwRecyclerMixin_suwDividerInsetStart, 0);
- int dividerInsetEnd =
- a.getDimensionPixelSize(R.styleable.SuwRecyclerMixin_suwDividerInsetEnd, 0);
- setDividerInsets(dividerInsetStart, dividerInsetEnd);
- }
-
- a.recycle();
+ this.recyclerView.addItemDecoration(dividerDecoration);
+ }
+
+ /**
+ * Parse XML attributes and configures this mixin and the recycler view accordingly. This should
+ * be called from the constructor of the layout.
+ *
+ * @param attrs The {@link AttributeSet} as passed into the constructor. Can be null if the layout
+ * was not created from XML.
+ * @param defStyleAttr The default style attribute as passed into the layout constructor. Can be 0
+ * if it is not needed.
+ */
+ public void parseAttributes(@Nullable AttributeSet attrs, int defStyleAttr) {
+ final Context context = templateLayout.getContext();
+ final TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.SuwRecyclerMixin, defStyleAttr, 0);
+
+ final int entries = a.getResourceId(R.styleable.SuwRecyclerMixin_android_entries, 0);
+ if (entries != 0) {
+ final ItemHierarchy inflated = new ItemInflater(context).inflate(entries);
+ final RecyclerItemAdapter adapter = new RecyclerItemAdapter(inflated);
+ adapter.setHasStableIds(a.getBoolean(R.styleable.SuwRecyclerMixin_suwHasStableIds, false));
+ setAdapter(adapter);
}
-
- /**
- * @return The recycler view contained in the layout, as marked by
- * {@code @id/suw_recycler_view}. This will return {@code null} if the recycler view
- * doesn't exist in the layout.
- */
- @SuppressWarnings("NullableProblems") // If clients guarantee that the template has a recycler
- // view, and call this after the template is inflated,
- // this will not return null.
- public RecyclerView getRecyclerView() {
- return mRecyclerView;
+ int dividerInset = a.getDimensionPixelSize(R.styleable.SuwRecyclerMixin_suwDividerInset, -1);
+ if (dividerInset != -1) {
+ setDividerInset(dividerInset);
+ } else {
+ int dividerInsetStart =
+ a.getDimensionPixelSize(R.styleable.SuwRecyclerMixin_suwDividerInsetStart, 0);
+ int dividerInsetEnd =
+ a.getDimensionPixelSize(R.styleable.SuwRecyclerMixin_suwDividerInsetEnd, 0);
+ setDividerInsets(dividerInsetStart, dividerInsetEnd);
}
- /**
- * Gets the header view of the recycler layout. This is useful for other mixins if they need to
- * access views within the header, usually via {@link TemplateLayout#findManagedViewById(int)}.
- */
- @SuppressWarnings("NullableProblems") // If clients guarantee that the template has a header,
- // this call will not return null.
- public View getHeader() {
- return mHeader;
+ a.recycle();
+ }
+
+ /**
+ * @return The recycler view contained in the layout, as marked by {@code @id/suw_recycler_view}.
+ * This will return {@code null} if the recycler view doesn't exist in the layout.
+ */
+ @SuppressWarnings("NullableProblems") // If clients guarantee that the template has a recycler
+ // view, and call this after the template is inflated,
+ // this will not return null.
+ public RecyclerView getRecyclerView() {
+ return recyclerView;
+ }
+
+ /**
+ * Gets the header view of the recycler layout. This is useful for other mixins if they need to
+ * access views within the header, usually via {@link TemplateLayout#findManagedViewById(int)}.
+ */
+ @SuppressWarnings("NullableProblems") // If clients guarantee that the template has a header,
+ // this call will not return null.
+ public View getHeader() {
+ return header;
+ }
+
+ /**
+ * Recycler mixin needs to update the dividers if the layout direction has changed. This method
+ * should be called when {@link View#onLayout(boolean, int, int, int, int)} of the template is
+ * called.
+ */
+ public void onLayout() {
+ if (divider == null) {
+ // Update divider in case layout direction has just been resolved
+ updateDivider();
}
-
- /**
- * Recycler mixin needs to update the dividers if the layout direction has changed. This method
- * should be called when {@link View#onLayout(boolean, int, int, int, int)} of the template
- * is called.
- */
- public void onLayout() {
- if (mDivider == null) {
- // Update divider in case layout direction has just been resolved
- updateDivider();
- }
+ }
+
+ /**
+ * Gets the adapter of the recycler view in this layout. If the adapter includes a header, this
+ * method will unwrap it and return the underlying adapter.
+ *
+ * @return The adapter, or {@code null} if the recycler view has no adapter.
+ */
+ public Adapter<? extends ViewHolder> getAdapter() {
+ @SuppressWarnings("unchecked") // RecyclerView.getAdapter returns raw type :(
+ final RecyclerView.Adapter<? extends ViewHolder> adapter = recyclerView.getAdapter();
+ if (adapter instanceof HeaderAdapter) {
+ return ((HeaderAdapter<? extends ViewHolder>) adapter).getWrappedAdapter();
}
-
- /**
- * Gets the adapter of the recycler view in this layout. If the adapter includes a header,
- * this method will unwrap it and return the underlying adapter.
- *
- * @return The adapter, or {@code null} if the recycler view has no adapter.
- */
- public Adapter<? extends ViewHolder> getAdapter() {
- @SuppressWarnings("unchecked") // RecyclerView.getAdapter returns raw type :(
- final RecyclerView.Adapter<? extends ViewHolder> adapter = mRecyclerView.getAdapter();
- if (adapter instanceof HeaderAdapter) {
- return ((HeaderAdapter<? extends ViewHolder>) adapter).getWrappedAdapter();
- }
- return adapter;
+ return adapter;
+ }
+
+ /** Sets the adapter on the recycler view in this layout. */
+ public void setAdapter(Adapter<? extends ViewHolder> adapter) {
+ recyclerView.setAdapter(adapter);
+ }
+
+ /** @deprecated Use {@link #setDividerInsets(int, int)} instead. */
+ @Deprecated
+ public void setDividerInset(int inset) {
+ setDividerInsets(inset, 0);
+ }
+
+ /**
+ * Sets the start inset of the divider. This will use the default divider drawable set in the
+ * theme and apply insets to it.
+ *
+ * @param start The number of pixels to inset on the "start" side of the list divider. Typically
+ * this will be either {@code @dimen/suw_items_glif_icon_divider_inset} or
+ * {@code @dimen/suw_items_glif_text_divider_inset}.
+ * @param end The number of pixels to inset on the "end" side of the list divider.
+ */
+ public void setDividerInsets(int start, int end) {
+ dividerInsetStart = start;
+ dividerInsetEnd = end;
+ updateDivider();
+ }
+
+ /**
+ * @return The number of pixels inset on the start side of the divider.
+ * @deprecated This is the same as {@link #getDividerInsetStart()}. Use that instead.
+ */
+ @Deprecated
+ public int getDividerInset() {
+ return getDividerInsetStart();
+ }
+
+ /** @return The number of pixels inset on the start side of the divider. */
+ public int getDividerInsetStart() {
+ return dividerInsetStart;
+ }
+
+ /** @return The number of pixels inset on the end side of the divider. */
+ public int getDividerInsetEnd() {
+ return dividerInsetEnd;
+ }
+
+ private void updateDivider() {
+ boolean shouldUpdate = true;
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ shouldUpdate = templateLayout.isLayoutDirectionResolved();
}
-
- /**
- * Sets the adapter on the recycler view in this layout.
- */
- public void setAdapter(Adapter<? extends ViewHolder> adapter) {
- mRecyclerView.setAdapter(adapter);
- }
-
- /**
- * @deprecated Use {@link #setDividerInsets(int, int)} instead.
- */
- @Deprecated
- public void setDividerInset(int inset) {
- setDividerInsets(inset, 0);
- }
-
- /**
- * Sets the start inset of the divider. This will use the default divider drawable set in the
- * theme and apply insets to it.
- *
- * @param start The number of pixels to inset on the "start" side of the list divider. Typically
- * this will be either {@code @dimen/suw_items_glif_icon_divider_inset} or
- * {@code @dimen/suw_items_glif_text_divider_inset}.
- * @param end The number of pixels to inset on the "end" side of the list divider.
- */
- public void setDividerInsets(int start, int end) {
- mDividerInsetStart = start;
- mDividerInsetEnd = end;
- updateDivider();
- }
-
- /**
- * @return The number of pixels inset on the start side of the divider.
- * @deprecated This is the same as {@link #getDividerInsetStart()}. Use that instead.
- */
- @Deprecated
- public int getDividerInset() {
- return getDividerInsetStart();
- }
-
- /**
- * @return The number of pixels inset on the start side of the divider.
- */
- public int getDividerInsetStart() {
- return mDividerInsetStart;
- }
-
- /**
- * @return The number of pixels inset on the end side of the divider.
- */
- public int getDividerInsetEnd() {
- return mDividerInsetEnd;
- }
-
- private void updateDivider() {
- boolean shouldUpdate = true;
- if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- shouldUpdate = mTemplateLayout.isLayoutDirectionResolved();
- }
- if (shouldUpdate) {
- if (mDefaultDivider == null) {
- mDefaultDivider = mDividerDecoration.getDivider();
- }
- mDivider = DrawableLayoutDirectionHelper.createRelativeInsetDrawable(
- mDefaultDivider,
- mDividerInsetStart /* start */,
- 0 /* top */,
- mDividerInsetEnd /* end */,
- 0 /* bottom */,
- mTemplateLayout);
- mDividerDecoration.setDivider(mDivider);
- }
- }
-
- /**
- * @return The drawable used as the divider.
- */
- public Drawable getDivider() {
- return mDivider;
- }
-
- /**
- * Sets the divider item decoration directly. This is a low level method which should be used
- * only if custom divider behavior is needed, for example if the divider should be shown /
- * hidden in some specific cases for view holders that cannot implement
- * {@link com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}.
- */
- public void setDividerItemDecoration(@NonNull DividerItemDecoration decoration) {
- mRecyclerView.removeItemDecoration(mDividerDecoration);
- mDividerDecoration = decoration;
- mRecyclerView.addItemDecoration(mDividerDecoration);
- updateDivider();
+ if (shouldUpdate) {
+ if (defaultDivider == null) {
+ defaultDivider = dividerDecoration.getDivider();
+ }
+ divider =
+ DrawableLayoutDirectionHelper.createRelativeInsetDrawable(
+ defaultDivider,
+ dividerInsetStart /* start */,
+ 0 /* top */,
+ dividerInsetEnd /* end */,
+ 0 /* bottom */,
+ templateLayout);
+ dividerDecoration.setDivider(divider);
}
+ }
+
+ /** @return The drawable used as the divider. */
+ public Drawable getDivider() {
+ return divider;
+ }
+
+ /**
+ * Sets the divider item decoration directly. This is a low level method which should be used only
+ * if custom divider behavior is needed, for example if the divider should be shown / hidden in
+ * some specific cases for view holders that cannot implement {@link
+ * com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}.
+ */
+ public void setDividerItemDecoration(@NonNull DividerItemDecoration decoration) {
+ recyclerView.removeItemDecoration(dividerDecoration);
+ dividerDecoration = decoration;
+ recyclerView.addItemDecoration(dividerDecoration);
+ updateDivider();
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegate.java b/library/recyclerview/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegate.java
index bfe8df2..8838c44 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegate.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegate.java
@@ -16,12 +16,10 @@
package com.android.setupwizardlib.template;
-import android.util.Log;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
-
+import android.util.Log;
import com.android.setupwizardlib.template.RequireScrollMixin.ScrollHandlingDelegate;
/**
@@ -30,55 +28,53 @@ import com.android.setupwizardlib.template.RequireScrollMixin.ScrollHandlingDele
*/
public class RecyclerViewScrollHandlingDelegate implements ScrollHandlingDelegate {
- private static final String TAG = "RVRequireScrollMixin";
+ private static final String TAG = "RVRequireScrollMixin";
- @Nullable
- private final RecyclerView mRecyclerView;
+ @Nullable private final RecyclerView recyclerView;
- @NonNull
- private final RequireScrollMixin mRequireScrollMixin;
+ @NonNull private final RequireScrollMixin requireScrollMixin;
- public RecyclerViewScrollHandlingDelegate(
- @NonNull RequireScrollMixin requireScrollMixin,
- @Nullable RecyclerView recyclerView) {
- mRequireScrollMixin = requireScrollMixin;
- mRecyclerView = recyclerView;
- }
+ public RecyclerViewScrollHandlingDelegate(
+ @NonNull RequireScrollMixin requireScrollMixin, @Nullable RecyclerView recyclerView) {
+ this.requireScrollMixin = requireScrollMixin;
+ this.recyclerView = recyclerView;
+ }
- private boolean canScrollDown() {
- if (mRecyclerView != null) {
- // Compatibility implementation of View#canScrollVertically
- final int offset = mRecyclerView.computeVerticalScrollOffset();
- final int range = mRecyclerView.computeVerticalScrollRange()
- - mRecyclerView.computeVerticalScrollExtent();
- return range != 0 && offset < range - 1;
- }
- return false;
+ private boolean canScrollDown() {
+ if (recyclerView != null) {
+ // Compatibility implementation of View#canScrollVertically
+ final int offset = recyclerView.computeVerticalScrollOffset();
+ final int range =
+ recyclerView.computeVerticalScrollRange() - recyclerView.computeVerticalScrollExtent();
+ return range != 0 && offset < range - 1;
}
+ return false;
+ }
- @Override
- public void startListening() {
- if (mRecyclerView != null) {
- mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- mRequireScrollMixin.notifyScrollabilityChange(canScrollDown());
- }
- });
-
- if (canScrollDown()) {
- mRequireScrollMixin.notifyScrollabilityChange(true);
+ @Override
+ public void startListening() {
+ if (this.recyclerView != null) {
+ this.recyclerView.addOnScrollListener(
+ new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ requireScrollMixin.notifyScrollabilityChange(canScrollDown());
}
- } else {
- Log.w(TAG, "Cannot require scroll. Recycler view is null.");
- }
+ });
+
+ if (canScrollDown()) {
+ requireScrollMixin.notifyScrollabilityChange(true);
+ }
+ } else {
+ Log.w(TAG, "Cannot require scroll. Recycler view is null.");
}
+ }
- @Override
- public void pageScrollDown() {
- if (mRecyclerView != null) {
- final int height = mRecyclerView.getHeight();
- mRecyclerView.smoothScrollBy(0, height);
- }
+ @Override
+ public void pageScrollDown() {
+ if (recyclerView != null) {
+ final int height = recyclerView.getHeight();
+ recyclerView.smoothScrollBy(0, height);
}
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/view/HeaderRecyclerView.java b/library/recyclerview/src/com/android/setupwizardlib/view/HeaderRecyclerView.java
index 0304b65..3808e11 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/view/HeaderRecyclerView.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/view/HeaderRecyclerView.java
@@ -19,259 +19,257 @@ package com.android.setupwizardlib.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
-
-import androidx.recyclerview.widget.RecyclerView;
-
import com.android.setupwizardlib.DividerItemDecoration;
import com.android.setupwizardlib.R;
/**
* A RecyclerView that can display a header item at the start of the list. The header can be set by
- * {@code app:suwHeader} in XML. Note that the header will not be inflated until a layout manager
- * is set.
+ * {@code app:suwHeader} in XML. Note that the header will not be inflated until a layout manager is
+ * set.
*/
public class HeaderRecyclerView extends RecyclerView {
- private static class HeaderViewHolder extends ViewHolder
- implements DividerItemDecoration.DividedViewHolder {
-
- HeaderViewHolder(View itemView) {
- super(itemView);
- }
-
- @Override
- public boolean isDividerAllowedAbove() {
- return false;
- }
+ private static class HeaderViewHolder extends ViewHolder
+ implements DividerItemDecoration.DividedViewHolder {
- @Override
- public boolean isDividerAllowedBelow() {
- return false;
- }
+ HeaderViewHolder(View itemView) {
+ super(itemView);
}
- /**
- * An adapter that can optionally add one header item to the RecyclerView.
- *
- * @param <CVH> Type of the content view holder. i.e. view holder type of the wrapped adapter.
- */
- public static class HeaderAdapter<CVH extends ViewHolder>
- extends RecyclerView.Adapter<ViewHolder> {
-
- private static final int HEADER_VIEW_TYPE = Integer.MAX_VALUE;
+ @Override
+ public boolean isDividerAllowedAbove() {
+ return false;
+ }
- private RecyclerView.Adapter<CVH> mAdapter;
- private View mHeader;
+ @Override
+ public boolean isDividerAllowedBelow() {
+ return false;
+ }
+ }
- private final AdapterDataObserver mObserver = new AdapterDataObserver() {
+ /**
+ * An adapter that can optionally add one header item to the RecyclerView.
+ *
+ * @param <CVH> Type of the content view holder. i.e. view holder type of the wrapped adapter.
+ */
+ public static class HeaderAdapter<CVH extends ViewHolder>
+ extends RecyclerView.Adapter<ViewHolder> {
- @Override
- public void onChanged() {
- notifyDataSetChanged();
- }
+ private static final int HEADER_VIEW_TYPE = Integer.MAX_VALUE;
- @Override
- public void onItemRangeChanged(int positionStart, int itemCount) {
- if (mHeader != null) {
- positionStart++;
- }
- notifyItemRangeChanged(positionStart, itemCount);
- }
+ private final RecyclerView.Adapter<CVH> adapter;
+ private View header;
- @Override
- public void onItemRangeInserted(int positionStart, int itemCount) {
- if (mHeader != null) {
- positionStart++;
- }
- notifyItemRangeInserted(positionStart, itemCount);
- }
+ private final AdapterDataObserver observer =
+ new AdapterDataObserver() {
- @Override
- public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
- if (mHeader != null) {
- fromPosition++;
- toPosition++;
- }
- // Why is there no notifyItemRangeMoved?
- for (int i = 0; i < itemCount; i++) {
- notifyItemMoved(fromPosition + i, toPosition + i);
- }
- }
+ @Override
+ public void onChanged() {
+ notifyDataSetChanged();
+ }
- @Override
- public void onItemRangeRemoved(int positionStart, int itemCount) {
- if (mHeader != null) {
- positionStart++;
- }
- notifyItemRangeRemoved(positionStart, itemCount);
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ if (header != null) {
+ positionStart++;
}
- };
-
- public HeaderAdapter(RecyclerView.Adapter<CVH> adapter) {
- mAdapter = adapter;
- mAdapter.registerAdapterDataObserver(mObserver);
- setHasStableIds(mAdapter.hasStableIds());
- }
+ notifyItemRangeChanged(positionStart, itemCount);
+ }
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- // Returning the same view (mHeader) results in crash ".. but view is not a real child."
- // The framework creates more than one instance of header because of "disappear"
- // animations applied on the header and this necessitates creation of another header
- // view to use after the animation. We work around this restriction by returning an
- // empty FrameLayout to which the header is attached using #onBindViewHolder method.
- if (viewType == HEADER_VIEW_TYPE) {
- FrameLayout frameLayout = new FrameLayout(parent.getContext());
- FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.WRAP_CONTENT);
- frameLayout.setLayoutParams(params);
- return new HeaderViewHolder(frameLayout);
- } else {
- return mAdapter.onCreateViewHolder(parent, viewType);
+ @Override
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ if (header != null) {
+ positionStart++;
}
- }
-
- @Override
- @SuppressWarnings("unchecked") // Non-header position always return type CVH
- public void onBindViewHolder(ViewHolder holder, int position) {
- if (mHeader != null) {
- position--;
+ notifyItemRangeInserted(positionStart, itemCount);
+ }
+
+ @Override
+ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ if (header != null) {
+ fromPosition++;
+ toPosition++;
}
-
- if (holder instanceof HeaderViewHolder) {
- if (mHeader == null) {
- throw new IllegalStateException("HeaderViewHolder cannot find mHeader");
- }
- if (mHeader.getParent() != null) {
- ((ViewGroup) mHeader.getParent()).removeView(mHeader);
- }
- FrameLayout mHeaderParent = (FrameLayout) holder.itemView;
- mHeaderParent.addView(mHeader);
- } else {
- mAdapter.onBindViewHolder((CVH) holder, position);
+ // Why is there no notifyItemRangeMoved?
+ for (int i = 0; i < itemCount; i++) {
+ notifyItemMoved(fromPosition + i, toPosition + i);
}
- }
+ }
- @Override
- public int getItemViewType(int position) {
- if (mHeader != null) {
- position--;
+ @Override
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ if (header != null) {
+ positionStart++;
}
- if (position < 0) {
- return HEADER_VIEW_TYPE;
- }
- return mAdapter.getItemViewType(position);
- }
-
- @Override
- public int getItemCount() {
- int count = mAdapter.getItemCount();
- if (mHeader != null) {
- count++;
- }
- return count;
- }
-
- @Override
- public long getItemId(int position) {
- if (mHeader != null) {
- position--;
- }
- if (position < 0) {
- return Long.MAX_VALUE;
- }
- return mAdapter.getItemId(position);
- }
-
- public void setHeader(View header) {
- mHeader = header;
- }
-
- public RecyclerView.Adapter<CVH> getWrappedAdapter() {
- return mAdapter;
- }
- }
-
- private View mHeader;
- private int mHeaderRes;
+ notifyItemRangeRemoved(positionStart, itemCount);
+ }
+ };
- public HeaderRecyclerView(Context context) {
- super(context);
- init(null, 0);
+ public HeaderAdapter(RecyclerView.Adapter<CVH> adapter) {
+ this.adapter = adapter;
+ this.adapter.registerAdapterDataObserver(observer);
+ setHasStableIds(this.adapter.hasStableIds());
}
- public HeaderRecyclerView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(attrs, 0);
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ // Returning the same view (header) results in crash ".. but view is not a real child."
+ // The framework creates more than one instance of header because of "disappear"
+ // animations applied on the header and this necessitates creation of another header
+ // view to use after the animation. We work around this restriction by returning an
+ // empty FrameLayout to which the header is attached using #onBindViewHolder method.
+ if (viewType == HEADER_VIEW_TYPE) {
+ FrameLayout frameLayout = new FrameLayout(parent.getContext());
+ FrameLayout.LayoutParams params =
+ new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
+ frameLayout.setLayoutParams(params);
+ return new HeaderViewHolder(frameLayout);
+ } else {
+ return adapter.onCreateViewHolder(parent, viewType);
+ }
}
- public HeaderRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init(attrs, defStyleAttr);
+ @Override
+ @SuppressWarnings("unchecked") // Non-header position always return type CVH
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ if (header != null) {
+ position--;
+ }
+
+ if (holder instanceof HeaderViewHolder) {
+ if (header == null) {
+ throw new IllegalStateException("HeaderViewHolder cannot find mHeader");
+ }
+ if (header.getParent() != null) {
+ ((ViewGroup) header.getParent()).removeView(header);
+ }
+ FrameLayout mHeaderParent = (FrameLayout) holder.itemView;
+ mHeaderParent.addView(header);
+ } else {
+ adapter.onBindViewHolder((CVH) holder, position);
+ }
}
- private void init(AttributeSet attrs, int defStyleAttr) {
- final TypedArray a = getContext().obtainStyledAttributes(attrs,
- R.styleable.SuwHeaderRecyclerView, defStyleAttr, 0);
- mHeaderRes = a.getResourceId(R.styleable.SuwHeaderRecyclerView_suwHeader, 0);
- a.recycle();
+ @Override
+ public int getItemViewType(int position) {
+ if (header != null) {
+ position--;
+ }
+ if (position < 0) {
+ return HEADER_VIEW_TYPE;
+ }
+ return adapter.getItemViewType(position);
}
@Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
-
- // Decoration-only headers should not count as an item for accessibility, adjust the
- // accessibility event to account for that.
- final int numberOfHeaders = mHeader != null ? 1 : 0;
- event.setItemCount(event.getItemCount() - numberOfHeaders);
- event.setFromIndex(Math.max(event.getFromIndex() - numberOfHeaders, 0));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- event.setToIndex(Math.max(event.getToIndex() - numberOfHeaders, 0));
- }
+ public int getItemCount() {
+ int count = adapter.getItemCount();
+ if (header != null) {
+ count++;
+ }
+ return count;
}
- /**
- * Gets the header view of this RecyclerView, or {@code null} if there are no headers.
- */
- public View getHeader() {
- return mHeader;
+ @Override
+ public long getItemId(int position) {
+ if (header != null) {
+ position--;
+ }
+ if (position < 0) {
+ return Long.MAX_VALUE;
+ }
+ return adapter.getItemId(position);
}
- /**
- * Set the view to use as the header of this recycler view.
- * Note: This must be called before setAdapter.
- */
public void setHeader(View header) {
- mHeader = header;
+ this.header = header;
}
- @Override
- public void setLayoutManager(LayoutManager layout) {
- super.setLayoutManager(layout);
- if (layout != null && mHeader == null && mHeaderRes != 0) {
- // Inflating a child view requires the layout manager to be set. Check here to see if
- // any header item is specified in XML and inflate them.
- final LayoutInflater inflater = LayoutInflater.from(getContext());
- mHeader = inflater.inflate(mHeaderRes, this, false);
- }
+ public RecyclerView.Adapter<CVH> getWrappedAdapter() {
+ return adapter;
}
-
- @Override
- @SuppressWarnings("rawtypes,unchecked") // RecyclerView.setAdapter uses raw type :(
- public void setAdapter(Adapter adapter) {
- if (mHeader != null && adapter != null) {
- final HeaderAdapter headerAdapter = new HeaderAdapter(adapter);
- headerAdapter.setHeader(mHeader);
- adapter = headerAdapter;
- }
- super.setAdapter(adapter);
+ }
+
+ private View header;
+ private int headerRes;
+
+ public HeaderRecyclerView(Context context) {
+ super(context);
+ init(null, 0);
+ }
+
+ public HeaderRecyclerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ public HeaderRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(attrs, defStyleAttr);
+ }
+
+ private void init(AttributeSet attrs, int defStyleAttr) {
+ final TypedArray a =
+ getContext()
+ .obtainStyledAttributes(attrs, R.styleable.SuwHeaderRecyclerView, defStyleAttr, 0);
+ headerRes = a.getResourceId(R.styleable.SuwHeaderRecyclerView_suwHeader, 0);
+ a.recycle();
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+
+ // Decoration-only headers should not count as an item for accessibility, adjust the
+ // accessibility event to account for that.
+ final int numberOfHeaders = header != null ? 1 : 0;
+ event.setItemCount(event.getItemCount() - numberOfHeaders);
+ event.setFromIndex(Math.max(event.getFromIndex() - numberOfHeaders, 0));
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ event.setToIndex(Math.max(event.getToIndex() - numberOfHeaders, 0));
+ }
+ }
+
+ /** Gets the header view of this RecyclerView, or {@code null} if there are no headers. */
+ public View getHeader() {
+ return header;
+ }
+
+ /**
+ * Set the view to use as the header of this recycler view. Note: This must be called before
+ * setAdapter.
+ */
+ public void setHeader(View header) {
+ this.header = header;
+ }
+
+ @Override
+ public void setLayoutManager(LayoutManager layout) {
+ super.setLayoutManager(layout);
+ if (layout != null && header == null && headerRes != 0) {
+ // Inflating a child view requires the layout manager to be set. Check here to see if
+ // any header item is specified in XML and inflate them.
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ header = inflater.inflate(headerRes, this, false);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes,unchecked") // RecyclerView.setAdapter uses raw type :(
+ public void setAdapter(Adapter adapter) {
+ if (header != null && adapter != null) {
+ final HeaderAdapter headerAdapter = new HeaderAdapter(adapter);
+ headerAdapter.setHeader(header);
+ adapter = headerAdapter;
}
+ super.setAdapter(adapter);
+ }
}
diff --git a/library/recyclerview/src/com/android/setupwizardlib/view/StickyHeaderRecyclerView.java b/library/recyclerview/src/com/android/setupwizardlib/view/StickyHeaderRecyclerView.java
index d51ea56..a5fa69c 100644
--- a/library/recyclerview/src/com/android/setupwizardlib/view/StickyHeaderRecyclerView.java
+++ b/library/recyclerview/src/com/android/setupwizardlib/view/StickyHeaderRecyclerView.java
@@ -32,112 +32,114 @@ import android.view.WindowInsets;
* to be drawn when the sticky element hits the top of the view.
*
* <p>There are a few things to note:
+ *
* <ol>
* <li>The view does not work well with padding. b/16190933
* <li>If fitsSystemWindows is true, then this will offset the sticking position by the height of
- * the system decorations at the top of the screen.
+ * the system decorations at the top of the screen.
* </ol>
*/
public class StickyHeaderRecyclerView extends HeaderRecyclerView {
- private View mSticky;
- private int mStatusBarInset = 0;
- private RectF mStickyRect = new RectF();
+ private View sticky;
+ private int statusBarInset = 0;
+ private final RectF stickyRect = new RectF();
- public StickyHeaderRecyclerView(Context context) {
- super(context);
- }
+ public StickyHeaderRecyclerView(Context context) {
+ super(context);
+ }
- public StickyHeaderRecyclerView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
+ public StickyHeaderRecyclerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
- public StickyHeaderRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
+ public StickyHeaderRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- if (mSticky == null) {
- updateStickyView();
- }
- if (mSticky != null) {
- final View headerView = getHeader();
- if (headerView != null && headerView.getHeight() == 0) {
- headerView.layout(0, -headerView.getMeasuredHeight(),
- headerView.getMeasuredWidth(), 0);
- }
- }
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (sticky == null) {
+ updateStickyView();
+ }
+ if (sticky != null) {
+ final View headerView = getHeader();
+ if (headerView != null && headerView.getHeight() == 0) {
+ headerView.layout(0, -headerView.getMeasuredHeight(), headerView.getMeasuredWidth(), 0);
+ }
}
+ }
- @Override
- protected void onMeasure(int widthSpec, int heightSpec) {
- super.onMeasure(widthSpec, heightSpec);
- if (mSticky != null) {
- measureChild(getHeader(), widthSpec, heightSpec);
- }
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ super.onMeasure(widthSpec, heightSpec);
+ if (sticky != null) {
+ measureChild(getHeader(), widthSpec, heightSpec);
}
+ }
- /**
- * Call this method when the "sticky" view has changed, so this view can update its internal
- * states as well.
- */
- public void updateStickyView() {
- final View header = getHeader();
- if (header != null) {
- mSticky = header.findViewWithTag("sticky");
- }
+ /**
+ * Call this method when the "sticky" view has changed, so this view can update its internal
+ * states as well.
+ */
+ public void updateStickyView() {
+ final View header = getHeader();
+ if (header != null) {
+ sticky = header.findViewWithTag("sticky");
}
+ }
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- if (mSticky != null) {
- final View headerView = getHeader();
- final int saveCount = canvas.save();
- // The view to draw when sticking to the top
- final View drawTarget = headerView != null ? headerView : mSticky;
- // The offset to draw the view at when sticky
- final int drawOffset = headerView != null ? mSticky.getTop() : 0;
- // Position of the draw target, relative to the outside of the scrollView
- final int drawTop = drawTarget.getTop();
- if (drawTop + drawOffset < mStatusBarInset || !drawTarget.isShown()) {
- // RecyclerView does not translate the canvas, so we can simply draw at the top
- mStickyRect.set(0, -drawOffset + mStatusBarInset, drawTarget.getWidth(),
- drawTarget.getHeight() - drawOffset + mStatusBarInset);
- canvas.translate(0, mStickyRect.top);
- canvas.clipRect(0, 0, drawTarget.getWidth(), drawTarget.getHeight());
- drawTarget.draw(canvas);
- } else {
- mStickyRect.setEmpty();
- }
- canvas.restoreToCount(saveCount);
- }
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ if (sticky != null) {
+ final View headerView = getHeader();
+ final int saveCount = canvas.save();
+ // The view to draw when sticking to the top
+ final View drawTarget = headerView != null ? headerView : sticky;
+ // The offset to draw the view at when sticky
+ final int drawOffset = headerView != null ? sticky.getTop() : 0;
+ // Position of the draw target, relative to the outside of the scrollView
+ final int drawTop = drawTarget.getTop();
+ if (drawTop + drawOffset < statusBarInset || !drawTarget.isShown()) {
+ // RecyclerView does not translate the canvas, so we can simply draw at the top
+ stickyRect.set(
+ 0,
+ -drawOffset + statusBarInset,
+ drawTarget.getWidth(),
+ drawTarget.getHeight() - drawOffset + statusBarInset);
+ canvas.translate(0, stickyRect.top);
+ canvas.clipRect(0, 0, drawTarget.getWidth(), drawTarget.getHeight());
+ drawTarget.draw(canvas);
+ } else {
+ stickyRect.setEmpty();
+ }
+ canvas.restoreToCount(saveCount);
}
+ }
- @Override
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- if (getFitsSystemWindows()) {
- mStatusBarInset = insets.getSystemWindowInsetTop();
- insets.replaceSystemWindowInsets(
- insets.getSystemWindowInsetLeft(),
- 0, /* top */
- insets.getSystemWindowInsetRight(),
- insets.getSystemWindowInsetBottom()
- );
- }
- return insets;
+ @Override
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if (getFitsSystemWindows()) {
+ statusBarInset = insets.getSystemWindowInsetTop();
+ insets.replaceSystemWindowInsets(
+ insets.getSystemWindowInsetLeft(),
+ 0, /* top */
+ insets.getSystemWindowInsetRight(),
+ insets.getSystemWindowInsetBottom());
}
+ return insets;
+ }
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (mStickyRect.contains(ev.getX(), ev.getY())) {
- ev.offsetLocation(-mStickyRect.left, -mStickyRect.top);
- return getHeader().dispatchTouchEvent(ev);
- } else {
- return super.dispatchTouchEvent(ev);
- }
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (stickyRect.contains(ev.getX(), ev.getY())) {
+ ev.offsetLocation(-stickyRect.left, -stickyRect.top);
+ return getHeader().dispatchTouchEvent(ev);
+ } else {
+ return super.dispatchTouchEvent(ev);
}
+ }
}
diff --git a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/items/RecyclerItemAdapterTest.java b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/items/RecyclerItemAdapterTest.java
index 6f42e84..bed736e 100644
--- a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/items/RecyclerItemAdapterTest.java
+++ b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/items/RecyclerItemAdapterTest.java
@@ -32,16 +32,13 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
+import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
+import android.widget.FrameLayout;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.widget.FrameLayout;
-
-import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
-
import com.android.setupwizardlib.items.RecyclerItemAdapter.PatchedLayerDrawable;
import com.android.setupwizardlib.test.R;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,111 +47,110 @@ import org.junit.runner.RunWith;
@SmallTest
public class RecyclerItemAdapterTest {
- private Item[] mItems = new Item[5];
- private ItemGroup mItemGroup = new ItemGroup();
-
- @Before
- public void setUp() throws Exception {
- for (int i = 0; i < 5; i++) {
- Item item = new Item();
- item.setTitle("TestTitle" + i);
- item.setId(i);
- // Layout resource: 0 -> 1, 1 -> 11, 2 -> 21, 3 -> 1, 4 -> 11.
- // (Resource IDs cannot be 0)
- item.setLayoutResource((i % 3) * 10 + 1);
- mItems[i] = item;
- mItemGroup.addChild(item);
- }
- }
-
- @Test
- public void testAdapter() {
- RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
- assertEquals("Adapter should have 5 items", 5, adapter.getItemCount());
- assertEquals("Adapter should return the first item", mItems[0], adapter.getItem(0));
- assertEquals("ID should be same as position", 2, adapter.getItemId(2));
-
- // ViewType is same as layout resource for RecyclerItemAdapter
- assertEquals("Second item should have view type 21", 21, adapter.getItemViewType(2));
- }
-
- @Test
- public void testGetRootItemHierarchy() {
- RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
- ItemHierarchy root = adapter.getRootItemHierarchy();
- assertSame("Root item hierarchy should be mItemGroup", mItemGroup, root);
- }
-
- @Test
- public void testPatchedLayerDrawableNoPadding() {
- ShapeDrawable child = new ShapeDrawable(new RectShape());
- child.setPadding(0, 0, 0, 0);
- PatchedLayerDrawable drawable = new PatchedLayerDrawable(new Drawable[] { child });
-
- Rect padding = new Rect();
- assertFalse("Patched layer drawable should not have padding", drawable.getPadding(padding));
- assertEquals(new Rect(0, 0, 0, 0), padding);
- }
-
- @Test
- public void testPatchedLayerDrawableWithPadding() {
- ShapeDrawable child = new ShapeDrawable(new RectShape());
- child.setPadding(10, 10, 10, 10);
- PatchedLayerDrawable drawable = new PatchedLayerDrawable(new Drawable[] { child });
-
- Rect padding = new Rect();
- assertTrue("Patched layer drawable should have padding", drawable.getPadding(padding));
- assertEquals(new Rect(10, 10, 10, 10), padding);
- }
-
- @Test
- public void testAdapterNotifications() {
- RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
- final AdapterDataObserver observer = mock(AdapterDataObserver.class);
- adapter.registerAdapterDataObserver(observer);
-
- mItems[0].setTitle("Child 1");
- verify(observer).onItemRangeChanged(eq(0), eq(1), anyObject());
-
- mItemGroup.removeChild(mItems[1]);
- verify(observer).onItemRangeRemoved(eq(1), eq(1));
-
- mItemGroup.addChild(mItems[1]);
- verify(observer).onItemRangeInserted(eq(4), eq(1));
- }
-
- @Test
- public void testCreateViewHolder() {
- RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
- FrameLayout parent = new FrameLayout(InstrumentationRegistry.getContext());
-
- final ItemViewHolder viewHolder =
- adapter.onCreateViewHolder(parent, R.layout.test_list_item);
- assertNotNull("Background should be set", viewHolder.itemView.getBackground());
- assertEquals("foobar", viewHolder.itemView.getTag());
- }
-
- @Test
- public void testCreateViewHolderNoBackground() {
- RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
- FrameLayout parent = new FrameLayout(InstrumentationRegistry.getContext());
-
- final ItemViewHolder viewHolder =
- adapter.onCreateViewHolder(parent, R.layout.test_list_item_no_background);
- assertNull("Background should be null", viewHolder.itemView.getBackground());
- }
-
- @Test
- public void testCreateViewHolderWithExistingBackground() {
- RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
- FrameLayout parent = new FrameLayout(InstrumentationRegistry.getContext());
-
- final ItemViewHolder viewHolder =
- adapter.onCreateViewHolder(parent, R.layout.test_existing_background);
- Drawable background = viewHolder.itemView.getBackground();
- assertTrue(background instanceof PatchedLayerDrawable);
-
- PatchedLayerDrawable layerDrawable = (PatchedLayerDrawable) background;
- assertTrue(layerDrawable.getDrawable(0) instanceof GradientDrawable);
+ private Item[] mItems = new Item[5];
+ private ItemGroup mItemGroup = new ItemGroup();
+
+ @Before
+ public void setUp() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ Item item = new Item();
+ item.setTitle("TestTitle" + i);
+ item.setId(i);
+ // Layout resource: 0 -> 1, 1 -> 11, 2 -> 21, 3 -> 1, 4 -> 11.
+ // (Resource IDs cannot be 0)
+ item.setLayoutResource((i % 3) * 10 + 1);
+ mItems[i] = item;
+ mItemGroup.addChild(item);
}
+ }
+
+ @Test
+ public void testAdapter() {
+ RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
+ assertEquals("Adapter should have 5 items", 5, adapter.getItemCount());
+ assertEquals("Adapter should return the first item", mItems[0], adapter.getItem(0));
+ assertEquals("ID should be same as position", 2, adapter.getItemId(2));
+
+ // ViewType is same as layout resource for RecyclerItemAdapter
+ assertEquals("Second item should have view type 21", 21, adapter.getItemViewType(2));
+ }
+
+ @Test
+ public void testGetRootItemHierarchy() {
+ RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
+ ItemHierarchy root = adapter.getRootItemHierarchy();
+ assertSame("Root item hierarchy should be mItemGroup", mItemGroup, root);
+ }
+
+ @Test
+ public void testPatchedLayerDrawableNoPadding() {
+ ShapeDrawable child = new ShapeDrawable(new RectShape());
+ child.setPadding(0, 0, 0, 0);
+ PatchedLayerDrawable drawable = new PatchedLayerDrawable(new Drawable[] {child});
+
+ Rect padding = new Rect();
+ assertFalse("Patched layer drawable should not have padding", drawable.getPadding(padding));
+ assertEquals(new Rect(0, 0, 0, 0), padding);
+ }
+
+ @Test
+ public void testPatchedLayerDrawableWithPadding() {
+ ShapeDrawable child = new ShapeDrawable(new RectShape());
+ child.setPadding(10, 10, 10, 10);
+ PatchedLayerDrawable drawable = new PatchedLayerDrawable(new Drawable[] {child});
+
+ Rect padding = new Rect();
+ assertTrue("Patched layer drawable should have padding", drawable.getPadding(padding));
+ assertEquals(new Rect(10, 10, 10, 10), padding);
+ }
+
+ @Test
+ public void testAdapterNotifications() {
+ RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
+ final AdapterDataObserver observer = mock(AdapterDataObserver.class);
+ adapter.registerAdapterDataObserver(observer);
+
+ mItems[0].setTitle("Child 1");
+ verify(observer).onItemRangeChanged(eq(0), eq(1), anyObject());
+
+ mItemGroup.removeChild(mItems[1]);
+ verify(observer).onItemRangeRemoved(eq(1), eq(1));
+
+ mItemGroup.addChild(mItems[1]);
+ verify(observer).onItemRangeInserted(eq(4), eq(1));
+ }
+
+ @Test
+ public void testCreateViewHolder() {
+ RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
+ FrameLayout parent = new FrameLayout(InstrumentationRegistry.getContext());
+
+ final ItemViewHolder viewHolder = adapter.onCreateViewHolder(parent, R.layout.test_list_item);
+ assertNotNull("Background should be set", viewHolder.itemView.getBackground());
+ assertEquals("foobar", viewHolder.itemView.getTag());
+ }
+
+ @Test
+ public void testCreateViewHolderNoBackground() {
+ RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
+ FrameLayout parent = new FrameLayout(InstrumentationRegistry.getContext());
+
+ final ItemViewHolder viewHolder =
+ adapter.onCreateViewHolder(parent, R.layout.test_list_item_no_background);
+ assertNull("Background should be null", viewHolder.itemView.getBackground());
+ }
+
+ @Test
+ public void testCreateViewHolderWithExistingBackground() {
+ RecyclerItemAdapter adapter = new RecyclerItemAdapter(mItemGroup);
+ FrameLayout parent = new FrameLayout(InstrumentationRegistry.getContext());
+
+ final ItemViewHolder viewHolder =
+ adapter.onCreateViewHolder(parent, R.layout.test_existing_background);
+ Drawable background = viewHolder.itemView.getBackground();
+ assertTrue(background instanceof PatchedLayerDrawable);
+
+ PatchedLayerDrawable layerDrawable = (PatchedLayerDrawable) background;
+ assertTrue(layerDrawable.getDrawable(0) instanceof GradientDrawable);
+ }
}
diff --git a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/template/RecyclerMixinTest.java b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/template/RecyclerMixinTest.java
index ece4bf9..f295b91 100644
--- a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/template/RecyclerMixinTest.java
+++ b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/template/RecyclerMixinTest.java
@@ -30,17 +30,14 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+import android.view.View;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,120 +48,119 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class RecyclerMixinTest {
- private Context mContext;
- private TemplateLayout mTemplateLayout;
+ private Context mContext;
+ private TemplateLayout mTemplateLayout;
- private RecyclerView mRecyclerView;
+ private RecyclerView mRecyclerView;
- @Mock
- private Adapter mAdapter;
+ @Mock private Adapter mAdapter;
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getTargetContext();
- mTemplateLayout = spy(new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content));
+ mContext = InstrumentationRegistry.getTargetContext();
+ mTemplateLayout =
+ spy(new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content));
- mRecyclerView = mock(RecyclerView.class, delegatesTo(new RecyclerView(mContext)));
+ mRecyclerView = mock(RecyclerView.class, delegatesTo(new RecyclerView(mContext)));
- doReturn(true).when(mTemplateLayout).isLayoutDirectionResolved();
- }
+ doReturn(true).when(mTemplateLayout).isLayoutDirectionResolved();
+ }
- @Test
- public void testGetRecyclerView() {
- RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
- assertSame(mRecyclerView, mixin.getRecyclerView());
- }
+ @Test
+ public void testGetRecyclerView() {
+ RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
+ assertSame(mRecyclerView, mixin.getRecyclerView());
+ }
- @Test
- public void testGetAdapter() {
- mRecyclerView.setAdapter(mAdapter);
+ @Test
+ public void testGetAdapter() {
+ mRecyclerView.setAdapter(mAdapter);
- RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
- assertSame(mAdapter, mixin.getAdapter());
- }
+ RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
+ assertSame(mAdapter, mixin.getAdapter());
+ }
- @Test
- public void testSetAdapter() {
- assertNull(mRecyclerView.getAdapter());
+ @Test
+ public void testSetAdapter() {
+ assertNull(mRecyclerView.getAdapter());
- RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
- mixin.setAdapter(mAdapter);
+ RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
+ mixin.setAdapter(mAdapter);
- assertSame(mAdapter, mRecyclerView.getAdapter());
- }
+ assertSame(mAdapter, mRecyclerView.getAdapter());
+ }
- @Test
- public void testDividerLegacyInset() {
- RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
- mixin.setDividerInset(123);
+ @Test
+ public void testDividerLegacyInset() {
+ RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
+ mixin.setDividerInset(123);
- assertEquals(123, mixin.getDividerInset());
+ assertEquals(123, mixin.getDividerInset());
- final Drawable divider = mixin.getDivider();
- InsetDrawable insetDrawable = (InsetDrawable) divider;
- Rect rect = new Rect();
- insetDrawable.getPadding(rect);
+ final Drawable divider = mixin.getDivider();
+ InsetDrawable insetDrawable = (InsetDrawable) divider;
+ Rect rect = new Rect();
+ insetDrawable.getPadding(rect);
- assertEquals(new Rect(123, 0, 0, 0), rect);
- }
+ assertEquals(new Rect(123, 0, 0, 0), rect);
+ }
- @Test
- public void testDividerInsets() {
- RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
- mixin.setDividerInsets(123, 456);
+ @Test
+ public void testDividerInsets() {
+ RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
+ mixin.setDividerInsets(123, 456);
- assertEquals(123, mixin.getDividerInsetStart());
- assertEquals(456, mixin.getDividerInsetEnd());
+ assertEquals(123, mixin.getDividerInsetStart());
+ assertEquals(456, mixin.getDividerInsetEnd());
- final Drawable divider = mixin.getDivider();
- InsetDrawable insetDrawable = (InsetDrawable) divider;
- Rect rect = new Rect();
- insetDrawable.getPadding(rect);
+ final Drawable divider = mixin.getDivider();
+ InsetDrawable insetDrawable = (InsetDrawable) divider;
+ Rect rect = new Rect();
+ insetDrawable.getPadding(rect);
- assertEquals(new Rect(123, 0, 456, 0), rect);
- }
+ assertEquals(new Rect(123, 0, 456, 0), rect);
+ }
- @Test
- public void testDividerInsetLegacyRtl() {
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
- doReturn(View.LAYOUT_DIRECTION_RTL).when(mTemplateLayout).getLayoutDirection();
+ @Test
+ public void testDividerInsetLegacyRtl() {
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ doReturn(View.LAYOUT_DIRECTION_RTL).when(mTemplateLayout).getLayoutDirection();
- RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
- mixin.setDividerInset(123);
+ RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
+ mixin.setDividerInset(123);
- assertEquals(123, mixin.getDividerInset());
+ assertEquals(123, mixin.getDividerInset());
- final Drawable divider = mixin.getDivider();
- InsetDrawable insetDrawable = (InsetDrawable) divider;
- Rect rect = new Rect();
- insetDrawable.getPadding(rect);
+ final Drawable divider = mixin.getDivider();
+ InsetDrawable insetDrawable = (InsetDrawable) divider;
+ Rect rect = new Rect();
+ insetDrawable.getPadding(rect);
- assertEquals(new Rect(0, 0, 123, 0), rect);
- }
- // else the test passes
+ assertEquals(new Rect(0, 0, 123, 0), rect);
}
+ // else the test passes
+ }
- @Test
- public void testDividerInsetsRtl() {
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
- doReturn(View.LAYOUT_DIRECTION_RTL).when(mTemplateLayout).getLayoutDirection();
+ @Test
+ public void testDividerInsetsRtl() {
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ doReturn(View.LAYOUT_DIRECTION_RTL).when(mTemplateLayout).getLayoutDirection();
- RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
- mixin.setDividerInsets(123, 456);
+ RecyclerMixin mixin = new RecyclerMixin(mTemplateLayout, mRecyclerView);
+ mixin.setDividerInsets(123, 456);
- assertEquals(123, mixin.getDividerInsetStart());
- assertEquals(456, mixin.getDividerInsetEnd());
+ assertEquals(123, mixin.getDividerInsetStart());
+ assertEquals(456, mixin.getDividerInsetEnd());
- final Drawable divider = mixin.getDivider();
- InsetDrawable insetDrawable = (InsetDrawable) divider;
- Rect rect = new Rect();
- insetDrawable.getPadding(rect);
+ final Drawable divider = mixin.getDivider();
+ InsetDrawable insetDrawable = (InsetDrawable) divider;
+ Rect rect = new Rect();
+ insetDrawable.getPadding(rect);
- assertEquals(new Rect(456, 0, 123, 0), rect);
- }
- // else the test passes
+ assertEquals(new Rect(456, 0, 123, 0), rect);
}
+ // else the test passes
+ }
}
diff --git a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/DividerItemDecorationTest.java b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/DividerItemDecorationTest.java
index 9cf33b9..a3a0cfe 100644
--- a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/DividerItemDecorationTest.java
+++ b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/DividerItemDecorationTest.java
@@ -28,17 +28,14 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
import com.android.setupwizardlib.DividerItemDecoration;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,176 +43,179 @@ import org.junit.runner.RunWith;
@SmallTest
public class DividerItemDecorationTest {
- @Test
- public void testDivider() {
- final DividerItemDecoration decoration = new DividerItemDecoration();
- Drawable divider = new ColorDrawable();
- decoration.setDivider(divider);
- assertSame("Divider should be same as set", divider, decoration.getDivider());
- }
+ @Test
+ public void testDivider() {
+ final DividerItemDecoration decoration = new DividerItemDecoration();
+ Drawable divider = new ColorDrawable();
+ decoration.setDivider(divider);
+ assertSame("Divider should be same as set", divider, decoration.getDivider());
+ }
+
+ @Test
+ public void testDividerHeight() {
+ final DividerItemDecoration decoration = new DividerItemDecoration();
+ decoration.setDividerHeight(123);
+ assertEquals("Divider height should be 123", 123, decoration.getDividerHeight());
+ }
+
+ @Test
+ public void testShouldDrawDividerBelowWithEitherCondition() {
+ // Set up the item decoration, with 1px red divider line
+ final DividerItemDecoration decoration = new DividerItemDecoration();
+ Drawable divider = new ColorDrawable(Color.RED);
+ decoration.setDivider(divider);
+ decoration.setDividerHeight(1);
+
+ Bitmap bitmap = drawDecoration(decoration, true, true);
+
+ // Draw the expected result on a bitmap
+ Bitmap expectedBitmap = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_4444);
+ Canvas expectedCanvas = new Canvas(expectedBitmap);
+ Paint paint = new Paint();
+ paint.setColor(Color.RED);
+ expectedCanvas.drawRect(0, 5, 20, 6, paint);
+ expectedCanvas.drawRect(0, 10, 20, 11, paint);
+ expectedCanvas.drawRect(0, 15, 20, 16, paint);
+ // Compare the two bitmaps
+ assertBitmapEquals(expectedBitmap, bitmap);
+
+ bitmap.recycle();
+ bitmap = drawDecoration(decoration, false, true);
+ // should still be the same.
+ assertBitmapEquals(expectedBitmap, bitmap);
+
+ bitmap.recycle();
+ bitmap = drawDecoration(decoration, true, false);
+ // last item should not have a divider below it now
+ paint.setColor(Color.TRANSPARENT);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ expectedCanvas.drawRect(0, 15, 20, 16, paint);
+ assertBitmapEquals(expectedBitmap, bitmap);
+
+ bitmap.recycle();
+ bitmap = drawDecoration(decoration, false, false);
+ // everything should be transparent now
+ expectedCanvas.drawRect(0, 5, 20, 6, paint);
+ expectedCanvas.drawRect(0, 10, 20, 11, paint);
+ assertBitmapEquals(expectedBitmap, bitmap);
+ }
+
+ @Test
+ public void testShouldDrawDividerBelowWithBothCondition() {
+ // Set up the item decoration, with 1px green divider line
+ final DividerItemDecoration decoration = new DividerItemDecoration();
+ Drawable divider = new ColorDrawable(Color.GREEN);
+ decoration.setDivider(divider);
+ decoration.setDividerHeight(1);
+ decoration.setDividerCondition(DividerItemDecoration.DIVIDER_CONDITION_BOTH);
+
+ Bitmap bitmap = drawDecoration(decoration, true, true);
+ Paint paint = new Paint();
+ paint.setColor(Color.GREEN);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
+ Bitmap expectedBitmap = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_4444);
+ Canvas expectedCanvas = new Canvas(expectedBitmap);
+ expectedCanvas.drawRect(0, 5, 20, 6, paint);
+ expectedCanvas.drawRect(0, 10, 20, 11, paint);
+ expectedCanvas.drawRect(0, 15, 20, 16, paint);
+ // Should have all the dividers
+ assertBitmapEquals(expectedBitmap, bitmap);
+
+ bitmap.recycle();
+ bitmap = drawDecoration(decoration, false, true);
+ paint.setColor(Color.TRANSPARENT);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ expectedCanvas.drawRect(0, 5, 20, 6, paint);
+ expectedCanvas.drawRect(0, 10, 20, 11, paint);
+ assertBitmapEquals(expectedBitmap, bitmap);
+
+ bitmap.recycle();
+ bitmap = drawDecoration(decoration, true, false);
+ // nothing should be drawn now.
+ expectedCanvas.drawRect(0, 15, 20, 16, paint);
+ assertBitmapEquals(expectedBitmap, bitmap);
+
+ bitmap.recycle();
+ bitmap = drawDecoration(decoration, false, false);
+ assertBitmapEquals(expectedBitmap, bitmap);
+ }
+
+ private Bitmap drawDecoration(
+ DividerItemDecoration decoration,
+ final boolean allowDividerAbove,
+ final boolean allowDividerBelow) {
+ // Set up the canvas to be drawn
+ Bitmap bitmap = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_4444);
+ Canvas canvas = new Canvas(bitmap);
+
+ final Context context = InstrumentationRegistry.getContext();
+ // Set up recycler view with vertical linear layout manager
+ RecyclerView testRecyclerView = new RecyclerView(context);
+ testRecyclerView.setLayoutManager(new LinearLayoutManager(context));
+
+ // Set up adapter with 3 items, each 5px tall
+ testRecyclerView.setAdapter(
+ new RecyclerView.Adapter() {
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
+ final View itemView = new View(context);
+ itemView.setMinimumWidth(20);
+ itemView.setMinimumHeight(5);
+ return ViewHolder.createInstance(itemView, allowDividerAbove, allowDividerBelow);
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {}
+
+ @Override
+ public int getItemCount() {
+ return 3;
+ }
+ });
- @Test
- public void testDividerHeight() {
- final DividerItemDecoration decoration = new DividerItemDecoration();
- decoration.setDividerHeight(123);
- assertEquals("Divider height should be 123", 123, decoration.getDividerHeight());
+ testRecyclerView.layout(0, 0, 20, 20);
+ decoration.onDraw(canvas, testRecyclerView, null);
+ return bitmap;
+ }
+
+ private void assertBitmapEquals(Bitmap expected, Bitmap actual) {
+ assertEquals("Width should be the same", expected.getWidth(), actual.getWidth());
+ assertEquals("Height should be the same", expected.getHeight(), actual.getHeight());
+ for (int x = 0; x < expected.getWidth(); x++) {
+ for (int y = 0; y < expected.getHeight(); y++) {
+ assertEquals(
+ "Pixel at (" + x + ", " + y + ") should be the same",
+ expected.getPixel(x, y),
+ actual.getPixel(x, y));
+ }
}
+ }
- @Test
- public void testShouldDrawDividerBelowWithEitherCondition() {
- // Set up the item decoration, with 1px red divider line
- final DividerItemDecoration decoration = new DividerItemDecoration();
- Drawable divider = new ColorDrawable(Color.RED);
- decoration.setDivider(divider);
- decoration.setDividerHeight(1);
-
- Bitmap bitmap = drawDecoration(decoration, true, true);
-
- // Draw the expected result on a bitmap
- Bitmap expectedBitmap = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_4444);
- Canvas expectedCanvas = new Canvas(expectedBitmap);
- Paint paint = new Paint();
- paint.setColor(Color.RED);
- expectedCanvas.drawRect(0, 5, 20, 6, paint);
- expectedCanvas.drawRect(0, 10, 20, 11, paint);
- expectedCanvas.drawRect(0, 15, 20, 16, paint);
- // Compare the two bitmaps
- assertBitmapEquals(expectedBitmap, bitmap);
-
- bitmap.recycle();
- bitmap = drawDecoration(decoration, false, true);
- // should still be the same.
- assertBitmapEquals(expectedBitmap, bitmap);
-
- bitmap.recycle();
- bitmap = drawDecoration(decoration, true, false);
- // last item should not have a divider below it now
- paint.setColor(Color.TRANSPARENT);
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
- expectedCanvas.drawRect(0, 15, 20, 16, paint);
- assertBitmapEquals(expectedBitmap, bitmap);
-
- bitmap.recycle();
- bitmap = drawDecoration(decoration, false, false);
- // everything should be transparent now
- expectedCanvas.drawRect(0, 5, 20, 6, paint);
- expectedCanvas.drawRect(0, 10, 20, 11, paint);
- assertBitmapEquals(expectedBitmap, bitmap);
+ private static class ViewHolder extends RecyclerView.ViewHolder
+ implements DividerItemDecoration.DividedViewHolder {
- }
+ private boolean mAllowDividerAbove;
+ private boolean mAllowDividerBelow;
- @Test
- public void testShouldDrawDividerBelowWithBothCondition() {
- // Set up the item decoration, with 1px green divider line
- final DividerItemDecoration decoration = new DividerItemDecoration();
- Drawable divider = new ColorDrawable(Color.GREEN);
- decoration.setDivider(divider);
- decoration.setDividerHeight(1);
- decoration.setDividerCondition(DividerItemDecoration.DIVIDER_CONDITION_BOTH);
-
- Bitmap bitmap = drawDecoration(decoration, true, true);
- Paint paint = new Paint();
- paint.setColor(Color.GREEN);
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
- Bitmap expectedBitmap = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_4444);
- Canvas expectedCanvas = new Canvas(expectedBitmap);
- expectedCanvas.drawRect(0, 5, 20, 6, paint);
- expectedCanvas.drawRect(0, 10, 20, 11, paint);
- expectedCanvas.drawRect(0, 15, 20, 16, paint);
- // Should have all the dividers
- assertBitmapEquals(expectedBitmap, bitmap);
-
- bitmap.recycle();
- bitmap = drawDecoration(decoration, false, true);
- paint.setColor(Color.TRANSPARENT);
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
- expectedCanvas.drawRect(0, 5, 20, 6, paint);
- expectedCanvas.drawRect(0, 10, 20, 11, paint);
- assertBitmapEquals(expectedBitmap, bitmap);
-
- bitmap.recycle();
- bitmap = drawDecoration(decoration, true, false);
- // nothing should be drawn now.
- expectedCanvas.drawRect(0, 15, 20, 16, paint);
- assertBitmapEquals(expectedBitmap, bitmap);
-
- bitmap.recycle();
- bitmap = drawDecoration(decoration, false, false);
- assertBitmapEquals(expectedBitmap, bitmap);
+ public static ViewHolder createInstance(
+ View itemView, boolean allowDividerAbove, boolean allowDividerBelow) {
+ return new ViewHolder(itemView, allowDividerAbove, allowDividerBelow);
}
- private Bitmap drawDecoration(DividerItemDecoration decoration, final boolean allowDividerAbove,
- final boolean allowDividerBelow) {
- // Set up the canvas to be drawn
- Bitmap bitmap = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_4444);
- Canvas canvas = new Canvas(bitmap);
-
- final Context context = InstrumentationRegistry.getContext();
- // Set up recycler view with vertical linear layout manager
- RecyclerView testRecyclerView = new RecyclerView(context);
- testRecyclerView.setLayoutManager(new LinearLayoutManager(context));
-
- // Set up adapter with 3 items, each 5px tall
- testRecyclerView.setAdapter(new RecyclerView.Adapter() {
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
- final View itemView = new View(context);
- itemView.setMinimumWidth(20);
- itemView.setMinimumHeight(5);
- return ViewHolder.createInstance(itemView, allowDividerAbove, allowDividerBelow);
- }
-
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
- }
-
- @Override
- public int getItemCount() {
- return 3;
- }
- });
-
- testRecyclerView.layout(0, 0, 20, 20);
- decoration.onDraw(canvas, testRecyclerView, null);
- return bitmap;
+ private ViewHolder(View itemView, boolean allowDividerAbove, boolean allowDividerBelow) {
+ super(itemView);
+ mAllowDividerAbove = allowDividerAbove;
+ mAllowDividerBelow = allowDividerBelow;
}
- private void assertBitmapEquals(Bitmap expected, Bitmap actual) {
- assertEquals("Width should be the same", expected.getWidth(), actual.getWidth());
- assertEquals("Height should be the same", expected.getHeight(), actual.getHeight());
- for (int x = 0; x < expected.getWidth(); x++) {
- for (int y = 0; y < expected.getHeight(); y++) {
- assertEquals("Pixel at (" + x + ", " + y + ") should be the same",
- expected.getPixel(x, y), actual.getPixel(x, y));
- }
- }
+ @Override
+ public boolean isDividerAllowedAbove() {
+ return mAllowDividerAbove;
}
- private static class ViewHolder extends RecyclerView.ViewHolder
- implements DividerItemDecoration.DividedViewHolder {
-
- private boolean mAllowDividerAbove;
- private boolean mAllowDividerBelow;
-
- public static ViewHolder createInstance(View itemView, boolean allowDividerAbove,
- boolean allowDividerBelow) {
- return new ViewHolder(itemView, allowDividerAbove, allowDividerBelow);
- }
-
- private ViewHolder(View itemView, boolean allowDividerAbove, boolean allowDividerBelow) {
- super(itemView);
- mAllowDividerAbove = allowDividerAbove;
- mAllowDividerBelow = allowDividerBelow;
- }
-
- @Override
- public boolean isDividerAllowedAbove() {
- return mAllowDividerAbove;
- }
-
- @Override
- public boolean isDividerAllowedBelow() {
- return mAllowDividerBelow;
- }
+ @Override
+ public boolean isDividerAllowedBelow() {
+ return mAllowDividerBelow;
}
+ }
}
diff --git a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifPreferenceLayoutTest.java b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifPreferenceLayoutTest.java
index 4d2876d..d55ba23 100644
--- a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifPreferenceLayoutTest.java
+++ b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifPreferenceLayoutTest.java
@@ -24,18 +24,15 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.GlifPreferenceLayout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,62 +41,63 @@ import org.junit.runner.RunWith;
@SmallTest
public class GlifPreferenceLayoutTest {
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeGlif_Light);
- }
-
- @Test
- public void testDefaultTemplate() {
- GlifPreferenceLayout layout = new GlifPreferenceLayout(mContext);
- assertPreferenceTemplateInflated(layout);
- }
-
- @Test
- public void testGetRecyclerView() {
- GlifPreferenceLayout layout = new GlifPreferenceLayout(mContext);
- assertPreferenceTemplateInflated(layout);
- assertNotNull("getRecyclerView should not be null", layout.getRecyclerView());
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext =
+ new ContextThemeWrapper(InstrumentationRegistry.getContext(), R.style.SuwThemeGlif_Light);
+ }
+
+ @Test
+ public void testDefaultTemplate() {
+ GlifPreferenceLayout layout = new GlifPreferenceLayout(mContext);
+ assertPreferenceTemplateInflated(layout);
+ }
+
+ @Test
+ public void testGetRecyclerView() {
+ GlifPreferenceLayout layout = new GlifPreferenceLayout(mContext);
+ assertPreferenceTemplateInflated(layout);
+ assertNotNull("getRecyclerView should not be null", layout.getRecyclerView());
+ }
+
+ @Test
+ public void testOnCreateRecyclerView() {
+ GlifPreferenceLayout layout = new GlifPreferenceLayout(mContext);
+ assertPreferenceTemplateInflated(layout);
+ final RecyclerView recyclerView =
+ layout.onCreateRecyclerView(
+ LayoutInflater.from(mContext), layout, null /* savedInstanceState */);
+ assertNotNull("RecyclerView created should not be null", recyclerView);
+ }
+
+ @Test
+ public void testDividerInset() {
+ GlifPreferenceLayout layout = new GlifPreferenceLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
+ assertPreferenceTemplateInflated(layout);
- @Test
- public void testOnCreateRecyclerView() {
- GlifPreferenceLayout layout = new GlifPreferenceLayout(mContext);
- assertPreferenceTemplateInflated(layout);
- final RecyclerView recyclerView = layout.onCreateRecyclerView(LayoutInflater.from(mContext),
- layout, null /* savedInstanceState */);
- assertNotNull("RecyclerView created should not be null", recyclerView);
- }
-
- @Test
- public void testDividerInset() {
- GlifPreferenceLayout layout = new GlifPreferenceLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertPreferenceTemplateInflated(layout);
+ layout.addView(
+ layout.onCreateRecyclerView(
+ LayoutInflater.from(mContext), layout, null /* savedInstanceState */));
- layout.addView(layout.onCreateRecyclerView(LayoutInflater.from(mContext), layout,
- null /* savedInstanceState */));
+ layout.setDividerInset(10);
+ assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
- layout.setDividerInset(10);
- assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
+ private void assertPreferenceTemplateInflated(GlifPreferenceLayout layout) {
+ View contentContainer = layout.findViewById(R.id.suw_layout_content);
+ assertTrue(
+ "@id/suw_layout_content should be a ViewGroup", contentContainer instanceof ViewGroup);
- private void assertPreferenceTemplateInflated(GlifPreferenceLayout layout) {
- View contentContainer = layout.findViewById(R.id.suw_layout_content);
- assertTrue("@id/suw_layout_content should be a ViewGroup",
- contentContainer instanceof ViewGroup);
-
- assertNotNull("Header text view should not be null",
- layout.findManagedViewById(R.id.suw_layout_title));
- assertNotNull("Icon view should not be null",
- layout.findManagedViewById(R.id.suw_layout_icon));
- }
+ assertNotNull(
+ "Header text view should not be null", layout.findManagedViewById(R.id.suw_layout_title));
+ assertNotNull("Icon view should not be null", layout.findManagedViewById(R.id.suw_layout_icon));
+ }
}
diff --git a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifRecyclerLayoutTest.java b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifRecyclerLayoutTest.java
index a68faf0..5db7db5 100644
--- a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifRecyclerLayoutTest.java
+++ b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/GlifRecyclerLayoutTest.java
@@ -26,20 +26,17 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.GlifRecyclerLayout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,130 +45,127 @@ import org.junit.runner.RunWith;
@SmallTest
public class GlifRecyclerLayoutTest {
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeGlif_Light);
- }
-
- @Test
- public void testDefaultTemplate() {
- GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
- assertRecyclerTemplateInflated(layout);
- }
-
- @Test
- public void testInflateFromXml() {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- GlifRecyclerLayout layout = (GlifRecyclerLayout)
- inflater.inflate(R.layout.test_glif_recycler_layout, null);
- assertRecyclerTemplateInflated(layout);
- }
-
- @Test
- public void testGetRecyclerView() {
- GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
- assertRecyclerTemplateInflated(layout);
- assertNotNull("getRecyclerView should not be null", layout.getRecyclerView());
- }
-
- @Test
- public void testAdapter() {
- GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
- assertRecyclerTemplateInflated(layout);
-
- final RecyclerView.Adapter adapter = createTestAdapter(1);
- layout.setAdapter(adapter);
-
- final RecyclerView.Adapter gotAdapter = layout.getAdapter();
- // Note: The wrapped adapter should be returned, not the HeaderAdapter.
- assertSame("Adapter got from GlifRecyclerLayout should be same as set",
- adapter, gotAdapter);
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext =
+ new ContextThemeWrapper(InstrumentationRegistry.getContext(), R.style.SuwThemeGlif_Light);
+ }
+
+ @Test
+ public void testDefaultTemplate() {
+ GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
+ assertRecyclerTemplateInflated(layout);
+ }
+
+ @Test
+ public void testInflateFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ GlifRecyclerLayout layout =
+ (GlifRecyclerLayout) inflater.inflate(R.layout.test_glif_recycler_layout, null);
+ assertRecyclerTemplateInflated(layout);
+ }
+
+ @Test
+ public void testGetRecyclerView() {
+ GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
+ assertRecyclerTemplateInflated(layout);
+ assertNotNull("getRecyclerView should not be null", layout.getRecyclerView());
+ }
+
+ @Test
+ public void testAdapter() {
+ GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
+ assertRecyclerTemplateInflated(layout);
+
+ final RecyclerView.Adapter adapter = createTestAdapter(1);
+ layout.setAdapter(adapter);
+
+ final RecyclerView.Adapter gotAdapter = layout.getAdapter();
+ // Note: The wrapped adapter should be returned, not the HeaderAdapter.
+ assertSame("Adapter got from GlifRecyclerLayout should be same as set", adapter, gotAdapter);
+ }
+
+ @Test
+ public void testLayout() {
+ GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
+ assertRecyclerTemplateInflated(layout);
+
+ layout.setAdapter(createTestAdapter(3));
+
+ layout.measure(
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+ layout.layout(0, 0, 500, 500);
+ // Test that the layout code doesn't crash.
+ }
+
+ @Test
+ public void testDividerInsetLegacy() {
+ GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
+ assertRecyclerTemplateInflated(layout);
- @Test
- public void testLayout() {
- GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
- assertRecyclerTemplateInflated(layout);
+ layout.setDividerInset(10);
+ assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
- layout.setAdapter(createTestAdapter(3));
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
- layout.measure(
- MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
- layout.layout(0, 0, 500, 500);
- // Test that the layout code doesn't crash.
+ @Test
+ public void testDividerInsets() {
+ GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
-
- @Test
- public void testDividerInsetLegacy() {
- GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertRecyclerTemplateInflated(layout);
-
- layout.setDividerInset(10);
- assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
-
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
-
- @Test
- public void testDividerInsets() {
- GlifRecyclerLayout layout = new GlifRecyclerLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertRecyclerTemplateInflated(layout);
-
- layout.setDividerInsets(10, 15);
- assertEquals("Divider inset start should be 10", 10, layout.getDividerInsetStart());
- assertEquals("Divider inset end should be 15", 15, layout.getDividerInsetEnd());
-
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
-
- @Test
- public void testTemplateWithNoRecyclerView() {
- try {
- new GlifRecyclerLayout(mContext, R.layout.suw_glif_template);
- fail("Creating GlifRecyclerLayout with no recycler view should throw exception");
- } catch (Exception e) {
- // pass
- }
- }
-
- private void assertRecyclerTemplateInflated(GlifRecyclerLayout layout) {
- View recyclerView = layout.findViewById(R.id.suw_recycler_view);
- assertTrue("@id/suw_recycler_view should be a RecyclerView",
- recyclerView instanceof RecyclerView);
-
- assertNotNull("Header text view should not be null",
- layout.findManagedViewById(R.id.suw_layout_title));
- assertNotNull("Icon view should not be null",
- layout.findManagedViewById(R.id.suw_layout_icon));
- }
-
- private Adapter createTestAdapter(final int itemCount) {
- return new RecyclerView.Adapter() {
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
- return new RecyclerView.ViewHolder(new View(parent.getContext())) {};
- }
-
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
- }
-
- @Override
- public int getItemCount() {
- return itemCount;
- }
- };
+ assertRecyclerTemplateInflated(layout);
+
+ layout.setDividerInsets(10, 15);
+ assertEquals("Divider inset start should be 10", 10, layout.getDividerInsetStart());
+ assertEquals("Divider inset end should be 15", 15, layout.getDividerInsetEnd());
+
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
+
+ @Test
+ public void testTemplateWithNoRecyclerView() {
+ try {
+ new GlifRecyclerLayout(mContext, R.layout.suw_glif_template);
+ fail("Creating GlifRecyclerLayout with no recycler view should throw exception");
+ } catch (Exception e) {
+ // pass
}
+ }
+
+ private void assertRecyclerTemplateInflated(GlifRecyclerLayout layout) {
+ View recyclerView = layout.findViewById(R.id.suw_recycler_view);
+ assertTrue(
+ "@id/suw_recycler_view should be a RecyclerView", recyclerView instanceof RecyclerView);
+
+ assertNotNull(
+ "Header text view should not be null", layout.findManagedViewById(R.id.suw_layout_title));
+ assertNotNull("Icon view should not be null", layout.findManagedViewById(R.id.suw_layout_icon));
+ }
+
+ private Adapter createTestAdapter(final int itemCount) {
+ return new RecyclerView.Adapter() {
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
+ return new RecyclerView.ViewHolder(new View(parent.getContext())) {};
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {}
+
+ @Override
+ public int getItemCount() {
+ return itemCount;
+ }
+ };
+ }
}
diff --git a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/HeaderRecyclerViewTest.java b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/HeaderRecyclerViewTest.java
index 9af68a7..3d0f9da 100644
--- a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/HeaderRecyclerViewTest.java
+++ b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/HeaderRecyclerViewTest.java
@@ -19,160 +19,143 @@ package com.android.setupwizardlib.test;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
+import androidx.recyclerview.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-
import com.android.setupwizardlib.view.HeaderRecyclerView.HeaderAdapter;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-/**
- * Test for {@link com.android.setupwizardlib.view.HeaderRecyclerView}
- */
+/** Test for {@link com.android.setupwizardlib.view.HeaderRecyclerView} */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class HeaderRecyclerViewTest {
- private TestAdapter mWrappedAdapter;
- private HeaderAdapter mHeaderAdapter;
-
- @Mock
- private RecyclerView.AdapterDataObserver mObserver;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mWrappedAdapter = new TestAdapter();
-
- mHeaderAdapter = new HeaderAdapter(mWrappedAdapter);
- mHeaderAdapter.registerAdapterDataObserver(mObserver);
- }
-
- /**
- * Test that notifyDataSetChanged gets propagated by HeaderRecyclerView's adapter.
- */
- @Test
- public void testNotifyChanged() {
- mWrappedAdapter.notifyDataSetChanged();
-
- verify(mObserver).onChanged();
+ private TestAdapter mWrappedAdapter;
+ private HeaderAdapter mHeaderAdapter;
+
+ @Mock private RecyclerView.AdapterDataObserver mObserver;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mWrappedAdapter = new TestAdapter();
+
+ mHeaderAdapter = new HeaderAdapter(mWrappedAdapter);
+ mHeaderAdapter.registerAdapterDataObserver(mObserver);
+ }
+
+ /** Test that notifyDataSetChanged gets propagated by HeaderRecyclerView's adapter. */
+ @Test
+ public void testNotifyChanged() {
+ mWrappedAdapter.notifyDataSetChanged();
+
+ verify(mObserver).onChanged();
+ }
+
+ /** Test that notifyItemChanged gets propagated by HeaderRecyclerView's adapter. */
+ @Test
+ public void testNotifyItemChangedNoHeader() {
+ mWrappedAdapter.notifyItemChanged(12);
+
+ verify(mObserver).onItemRangeChanged(eq(12), eq(1), eq(null));
+ }
+
+ /**
+ * Test that notifyItemChanged gets propagated by HeaderRecyclerView's adapter and adds 1 to the
+ * position for the extra header items.
+ */
+ @Test
+ public void testNotifyItemChangedWithHeader() {
+ mHeaderAdapter.setHeader(new View(InstrumentationRegistry.getTargetContext()));
+ mWrappedAdapter.notifyItemChanged(12);
+
+ verify(mObserver).onItemRangeChanged(eq(13), eq(1), eq(null));
+ }
+
+ /** Test that notifyItemInserted gets propagated by HeaderRecyclerView's adapter. */
+ @Test
+ public void testNotifyItemInsertedNoHeader() {
+ mWrappedAdapter.notifyItemInserted(12);
+
+ verify(mObserver).onItemRangeInserted(eq(12), eq(1));
+ }
+
+ /**
+ * Test that notifyItemInserted gets propagated by HeaderRecyclerView's adapter and adds 1 to the
+ * position for the extra header item.
+ */
+ @Test
+ public void testNotifyItemInsertedWithHeader() {
+ mHeaderAdapter.setHeader(new View(InstrumentationRegistry.getTargetContext()));
+ mWrappedAdapter.notifyItemInserted(12);
+
+ verify(mObserver).onItemRangeInserted(eq(13), eq(1));
+ }
+
+ /** Test that notifyItemRemoved gets propagated by HeaderRecyclerView's adapter. */
+ @Test
+ public void testNotifyItemRemovedNoHeader() {
+ mWrappedAdapter.notifyItemRemoved(12);
+
+ verify(mObserver).onItemRangeRemoved(eq(12), eq(1));
+ }
+
+ /**
+ * Test that notifyItemRemoved gets propagated by HeaderRecyclerView's adapter and adds 1 to the
+ * position for the extra header item.
+ */
+ @Test
+ public void testNotifyItemRemovedWithHeader() {
+ mHeaderAdapter.setHeader(new View(InstrumentationRegistry.getTargetContext()));
+ mWrappedAdapter.notifyItemRemoved(12);
+
+ verify(mObserver).onItemRangeRemoved(eq(13), eq(1));
+ }
+
+ /** Test that notifyItemMoved gets propagated by HeaderRecyclerView's adapter. */
+ @Test
+ public void testNotifyItemMovedNoHeader() {
+ mWrappedAdapter.notifyItemMoved(12, 18);
+
+ verify(mObserver).onItemRangeMoved(eq(12), eq(18), eq(1));
+ }
+
+ /**
+ * Test that notifyItemMoved gets propagated by HeaderRecyclerView's adapter and adds 1 to the
+ * position for the extra header item.
+ */
+ @Test
+ public void testNotifyItemMovedWithHeader() {
+ mHeaderAdapter.setHeader(new View(InstrumentationRegistry.getTargetContext()));
+ mWrappedAdapter.notifyItemMoved(12, 18);
+
+ verify(mObserver).onItemRangeMoved(eq(13), eq(19), eq(1));
+ }
+
+ /**
+ * Test adapter to be wrapped inside {@link HeaderAdapter} to to send item change notifications.
+ */
+ public static class TestAdapter extends RecyclerView.Adapter {
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
+ return null;
}
- /**
- * Test that notifyItemChanged gets propagated by HeaderRecyclerView's adapter.
- */
- @Test
- public void testNotifyItemChangedNoHeader() {
- mWrappedAdapter.notifyItemChanged(12);
-
- verify(mObserver).onItemRangeChanged(eq(12), eq(1), eq(null));
- }
-
- /**
- * Test that notifyItemChanged gets propagated by HeaderRecyclerView's adapter and adds 1 to the
- * position for the extra header items.
- */
- @Test
- public void testNotifyItemChangedWithHeader() {
- mHeaderAdapter.setHeader(new View(InstrumentationRegistry.getTargetContext()));
- mWrappedAdapter.notifyItemChanged(12);
-
- verify(mObserver).onItemRangeChanged(eq(13), eq(1), eq(null));
- }
-
- /**
- * Test that notifyItemInserted gets propagated by HeaderRecyclerView's adapter.
- */
- @Test
- public void testNotifyItemInsertedNoHeader() {
- mWrappedAdapter.notifyItemInserted(12);
-
- verify(mObserver).onItemRangeInserted(eq(12), eq(1));
- }
-
- /**
- * Test that notifyItemInserted gets propagated by HeaderRecyclerView's adapter and adds 1 to
- * the position for the extra header item.
- */
- @Test
- public void testNotifyItemInsertedWithHeader() {
- mHeaderAdapter.setHeader(new View(InstrumentationRegistry.getTargetContext()));
- mWrappedAdapter.notifyItemInserted(12);
-
- verify(mObserver).onItemRangeInserted(eq(13), eq(1));
- }
-
- /**
- * Test that notifyItemRemoved gets propagated by HeaderRecyclerView's adapter.
- */
- @Test
- public void testNotifyItemRemovedNoHeader() {
- mWrappedAdapter.notifyItemRemoved(12);
-
- verify(mObserver).onItemRangeRemoved(eq(12), eq(1));
- }
-
- /**
- * Test that notifyItemRemoved gets propagated by HeaderRecyclerView's adapter and adds 1 to
- * the position for the extra header item.
- */
- @Test
- public void testNotifyItemRemovedWithHeader() {
- mHeaderAdapter.setHeader(new View(InstrumentationRegistry.getTargetContext()));
- mWrappedAdapter.notifyItemRemoved(12);
-
- verify(mObserver).onItemRangeRemoved(eq(13), eq(1));
- }
-
- /**
- * Test that notifyItemMoved gets propagated by HeaderRecyclerView's adapter.
- */
- @Test
- public void testNotifyItemMovedNoHeader() {
- mWrappedAdapter.notifyItemMoved(12, 18);
-
- verify(mObserver).onItemRangeMoved(eq(12), eq(18), eq(1));
- }
-
- /**
- * Test that notifyItemMoved gets propagated by HeaderRecyclerView's adapter and adds 1 to
- * the position for the extra header item.
- */
- @Test
- public void testNotifyItemMovedWithHeader() {
- mHeaderAdapter.setHeader(new View(InstrumentationRegistry.getTargetContext()));
- mWrappedAdapter.notifyItemMoved(12, 18);
-
- verify(mObserver).onItemRangeMoved(eq(13), eq(19), eq(1));
- }
-
- /**
- * Test adapter to be wrapped inside {@link HeaderAdapter} to to send item change notifications.
- */
- public static class TestAdapter extends RecyclerView.Adapter {
-
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
- return null;
- }
-
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
- }
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {}
- @Override
- public int getItemCount() {
- return 0;
- }
+ @Override
+ public int getItemCount() {
+ return 0;
}
+ }
}
diff --git a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardPreferenceLayoutTest.java b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardPreferenceLayoutTest.java
index 316793f..39929dc 100644
--- a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardPreferenceLayoutTest.java
+++ b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardPreferenceLayoutTest.java
@@ -24,18 +24,15 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.recyclerview.widget.RecyclerView;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.SetupWizardPreferenceLayout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,62 +41,65 @@ import org.junit.runner.RunWith;
@SmallTest
public class SetupWizardPreferenceLayoutTest {
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeMaterial_Light);
- }
-
- @Test
- public void testDefaultTemplate() {
- SetupWizardPreferenceLayout layout = new SetupWizardPreferenceLayout(mContext);
- assertPreferenceTemplateInflated(layout);
- }
-
- @Test
- public void testGetRecyclerView() {
- SetupWizardPreferenceLayout layout = new SetupWizardPreferenceLayout(mContext);
- assertPreferenceTemplateInflated(layout);
- assertNotNull("getRecyclerView should not be null", layout.getRecyclerView());
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext =
+ new ContextThemeWrapper(
+ InstrumentationRegistry.getContext(), R.style.SuwThemeMaterial_Light);
+ }
+
+ @Test
+ public void testDefaultTemplate() {
+ SetupWizardPreferenceLayout layout = new SetupWizardPreferenceLayout(mContext);
+ assertPreferenceTemplateInflated(layout);
+ }
+
+ @Test
+ public void testGetRecyclerView() {
+ SetupWizardPreferenceLayout layout = new SetupWizardPreferenceLayout(mContext);
+ assertPreferenceTemplateInflated(layout);
+ assertNotNull("getRecyclerView should not be null", layout.getRecyclerView());
+ }
+
+ @Test
+ public void testOnCreateRecyclerView() {
+ SetupWizardPreferenceLayout layout = new SetupWizardPreferenceLayout(mContext);
+ assertPreferenceTemplateInflated(layout);
+ final RecyclerView recyclerView =
+ layout.onCreateRecyclerView(
+ LayoutInflater.from(mContext), layout, null /* savedInstanceState */);
+ assertNotNull("RecyclerView created should not be null", recyclerView);
+ }
+
+ @Test
+ public void testDividerInset() {
+ SetupWizardPreferenceLayout layout = new SetupWizardPreferenceLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
+ assertPreferenceTemplateInflated(layout);
- @Test
- public void testOnCreateRecyclerView() {
- SetupWizardPreferenceLayout layout = new SetupWizardPreferenceLayout(mContext);
- assertPreferenceTemplateInflated(layout);
- final RecyclerView recyclerView = layout.onCreateRecyclerView(LayoutInflater.from(mContext),
- layout, null /* savedInstanceState */);
- assertNotNull("RecyclerView created should not be null", recyclerView);
- }
-
- @Test
- public void testDividerInset() {
- SetupWizardPreferenceLayout layout = new SetupWizardPreferenceLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertPreferenceTemplateInflated(layout);
+ layout.addView(
+ layout.onCreateRecyclerView(
+ LayoutInflater.from(mContext), layout, null /* savedInstanceState */));
- layout.addView(layout.onCreateRecyclerView(LayoutInflater.from(mContext), layout,
- null /* savedInstanceState */));
+ layout.setDividerInset(10);
+ assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
- layout.setDividerInset(10);
- assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
+ private void assertPreferenceTemplateInflated(SetupWizardPreferenceLayout layout) {
+ View contentContainer = layout.findViewById(R.id.suw_layout_content);
+ assertTrue(
+ "@id/suw_layout_content should be a ViewGroup", contentContainer instanceof ViewGroup);
- private void assertPreferenceTemplateInflated(SetupWizardPreferenceLayout layout) {
- View contentContainer = layout.findViewById(R.id.suw_layout_content);
- assertTrue("@id/suw_layout_content should be a ViewGroup",
- contentContainer instanceof ViewGroup);
-
- assertNotNull("Header text view should not be null",
- layout.findManagedViewById(R.id.suw_layout_title));
- assertNotNull("Decoration view should not be null",
- layout.findManagedViewById(R.id.suw_layout_decor));
- }
+ assertNotNull(
+ "Header text view should not be null", layout.findManagedViewById(R.id.suw_layout_title));
+ assertNotNull(
+ "Decoration view should not be null", layout.findManagedViewById(R.id.suw_layout_decor));
+ }
}
diff --git a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardRecyclerLayoutTest.java b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardRecyclerLayoutTest.java
index bbe773b..46a665d 100644
--- a/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardRecyclerLayoutTest.java
+++ b/library/recyclerview/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardRecyclerLayoutTest.java
@@ -26,21 +26,18 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.SetupWizardRecyclerLayout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,133 +46,129 @@ import org.junit.runner.RunWith;
@SmallTest
public class SetupWizardRecyclerLayoutTest {
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeMaterial_Light);
- }
-
- @Test
- public void testDefaultTemplate() {
- SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
- assertRecyclerTemplateInflated(layout);
- }
-
- @Test
- public void testInflateFromXml() {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- SetupWizardRecyclerLayout layout = (SetupWizardRecyclerLayout)
- inflater.inflate(R.layout.test_recycler_layout, null);
- assertRecyclerTemplateInflated(layout);
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext =
+ new ContextThemeWrapper(
+ InstrumentationRegistry.getContext(), R.style.SuwThemeMaterial_Light);
+ }
+
+ @Test
+ public void testDefaultTemplate() {
+ SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
+ assertRecyclerTemplateInflated(layout);
+ }
+
+ @Test
+ public void testInflateFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ SetupWizardRecyclerLayout layout =
+ (SetupWizardRecyclerLayout) inflater.inflate(R.layout.test_recycler_layout, null);
+ assertRecyclerTemplateInflated(layout);
+ }
+
+ @Test
+ public void testGetRecyclerView() {
+ SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
+ assertRecyclerTemplateInflated(layout);
+ assertNotNull("getRecyclerView should not be null", layout.getRecyclerView());
+ }
+
+ @Test
+ public void testAdapter() {
+ SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
+ assertRecyclerTemplateInflated(layout);
+
+ final Adapter adapter = createTestAdapter(1);
+ layout.setAdapter(adapter);
+
+ final Adapter gotAdapter = layout.getAdapter();
+ // Note: The wrapped adapter should be returned, not the HeaderAdapter.
+ assertSame("Adapter got from SetupWizardLayout should be same as set", adapter, gotAdapter);
+ }
+
+ @Test
+ public void testLayout() {
+ SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
+ assertRecyclerTemplateInflated(layout);
+
+ layout.setAdapter(createTestAdapter(3));
+
+ layout.measure(
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
+ layout.layout(0, 0, 500, 500);
+ // Test that the layout code doesn't crash.
+ }
+
+ @Test
+ public void testDividerInsetLegacy() {
+ SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
+ assertRecyclerTemplateInflated(layout);
- @Test
- public void testGetRecyclerView() {
- SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
- assertRecyclerTemplateInflated(layout);
- assertNotNull("getRecyclerView should not be null", layout.getRecyclerView());
- }
-
- @Test
- public void testAdapter() {
- SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
- assertRecyclerTemplateInflated(layout);
-
- final Adapter adapter = createTestAdapter(1);
- layout.setAdapter(adapter);
-
- final Adapter gotAdapter = layout.getAdapter();
- // Note: The wrapped adapter should be returned, not the HeaderAdapter.
- assertSame("Adapter got from SetupWizardLayout should be same as set",
- adapter, gotAdapter);
- }
-
- @Test
- public void testLayout() {
- SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
- assertRecyclerTemplateInflated(layout);
-
- layout.setAdapter(createTestAdapter(3));
-
- layout.measure(
- MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY));
- layout.layout(0, 0, 500, 500);
- // Test that the layout code doesn't crash.
- }
-
- @Test
- public void testDividerInsetLegacy() {
- SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertRecyclerTemplateInflated(layout);
+ layout.setDividerInset(10);
+ assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
- layout.setDividerInset(10);
- assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ @Test
+ public void testDividerInsets() {
+ SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
-
- @Test
- public void testDividerInsets() {
- SetupWizardRecyclerLayout layout = new SetupWizardRecyclerLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertRecyclerTemplateInflated(layout);
-
- layout.setDividerInsets(10, 15);
- assertEquals("Divider inset start should be 10", 10, layout.getDividerInsetStart());
- assertEquals("Divider inset end should be 15", 15, layout.getDividerInsetEnd());
-
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
-
- @Test
- public void testTemplateWithNoRecyclerView() {
- try {
- new SetupWizardRecyclerLayout(
- mContext,
- R.layout.suw_glif_template,
- R.id.suw_recycler_view);
- fail("Creating SetupWizardRecyclerLayout with no recycler view should throw exception");
- } catch (Exception e) {
- // pass
- }
- }
-
- private void assertRecyclerTemplateInflated(SetupWizardRecyclerLayout layout) {
- View recyclerView = layout.findViewById(R.id.suw_recycler_view);
- assertTrue("@id/suw_recycler_view should be a RecyclerView",
- recyclerView instanceof RecyclerView);
-
- assertNotNull("Header text view should not be null",
- layout.findManagedViewById(R.id.suw_layout_title));
- assertNotNull("Decoration view should not be null",
- layout.findManagedViewById(R.id.suw_layout_decor));
- }
-
- private Adapter createTestAdapter(final int itemCount) {
- return new Adapter() {
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
- return new ViewHolder(new View(parent.getContext())) {};
- }
-
- @Override
- public void onBindViewHolder(ViewHolder viewHolder, int position) {
- }
-
- @Override
- public int getItemCount() {
- return itemCount;
- }
- };
+ assertRecyclerTemplateInflated(layout);
+
+ layout.setDividerInsets(10, 15);
+ assertEquals("Divider inset start should be 10", 10, layout.getDividerInsetStart());
+ assertEquals("Divider inset end should be 15", 15, layout.getDividerInsetEnd());
+
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
+
+ @Test
+ public void testTemplateWithNoRecyclerView() {
+ try {
+ new SetupWizardRecyclerLayout(mContext, R.layout.suw_glif_template, R.id.suw_recycler_view);
+ fail("Creating SetupWizardRecyclerLayout with no recycler view should throw exception");
+ } catch (Exception e) {
+ // pass
}
+ }
+
+ private void assertRecyclerTemplateInflated(SetupWizardRecyclerLayout layout) {
+ View recyclerView = layout.findViewById(R.id.suw_recycler_view);
+ assertTrue(
+ "@id/suw_recycler_view should be a RecyclerView", recyclerView instanceof RecyclerView);
+
+ assertNotNull(
+ "Header text view should not be null", layout.findManagedViewById(R.id.suw_layout_title));
+ assertNotNull(
+ "Decoration view should not be null", layout.findManagedViewById(R.id.suw_layout_decor));
+ }
+
+ private Adapter createTestAdapter(final int itemCount) {
+ return new Adapter() {
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
+ return new ViewHolder(new View(parent.getContext())) {};
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder viewHolder, int position) {}
+
+ @Override
+ public int getItemCount() {
+ return itemCount;
+ }
+ };
+ }
}
diff --git a/library/recyclerview/test/robotest/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegateTest.java b/library/recyclerview/test/robotest/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegateTest.java
index 6fa4c54..bcb51a8 100644
--- a/library/recyclerview/test/robotest/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegateTest.java
+++ b/library/recyclerview/test/robotest/src/com/android/setupwizardlib/template/RecyclerViewScrollHandlingDelegateTest.java
@@ -26,63 +26,60 @@ import static org.robolectric.RuntimeEnvironment.application;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
-
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
-@RunWith(SuwLibRobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
+@RunWith(RobolectricTestRunner.class)
public class RecyclerViewScrollHandlingDelegateTest {
- @Mock
- private RequireScrollMixin mRequireScrollMixin;
-
- private RecyclerView mRecyclerView;
- private RecyclerViewScrollHandlingDelegate mDelegate;
- private ArgumentCaptor<OnScrollListener> mListenerCaptor;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mRecyclerView = spy(new RecyclerView(application));
- doReturn(20).when(mRecyclerView).computeVerticalScrollRange();
- doReturn(0).when(mRecyclerView).computeVerticalScrollExtent();
- doReturn(0).when(mRecyclerView).computeVerticalScrollOffset();
- mListenerCaptor = ArgumentCaptor.forClass(OnScrollListener.class);
- doNothing().when(mRecyclerView).addOnScrollListener(mListenerCaptor.capture());
-
- mDelegate = new RecyclerViewScrollHandlingDelegate(mRequireScrollMixin, mRecyclerView);
- mRecyclerView.layout(0, 0, 50, 50);
- }
-
- @Test
- public void testRequireScroll() {
- mDelegate.startListening();
- verify(mRequireScrollMixin).notifyScrollabilityChange(true);
- }
-
- @Test
- public void testScrolledToBottom() {
- mDelegate.startListening();
- verify(mRequireScrollMixin).notifyScrollabilityChange(true);
-
- doReturn(20).when(mRecyclerView).computeVerticalScrollOffset();
- mListenerCaptor.getValue().onScrolled(mRecyclerView, 0, 20);
-
- verify(mRequireScrollMixin).notifyScrollabilityChange(false);
- }
-
- @Test
- public void testClickScrollButton() {
- mDelegate.pageScrollDown();
- verify(mRecyclerView).smoothScrollBy(anyInt(), eq(50));
- }
+ @Mock private RequireScrollMixin mRequireScrollMixin;
+
+ private RecyclerView mRecyclerView;
+ private RecyclerViewScrollHandlingDelegate mDelegate;
+ private ArgumentCaptor<OnScrollListener> mListenerCaptor;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mRecyclerView = spy(new RecyclerView(application));
+ doReturn(20).when(mRecyclerView).computeVerticalScrollRange();
+ doReturn(0).when(mRecyclerView).computeVerticalScrollExtent();
+ doReturn(0).when(mRecyclerView).computeVerticalScrollOffset();
+ mListenerCaptor = ArgumentCaptor.forClass(OnScrollListener.class);
+ doNothing().when(mRecyclerView).addOnScrollListener(mListenerCaptor.capture());
+
+ mDelegate = new RecyclerViewScrollHandlingDelegate(mRequireScrollMixin, mRecyclerView);
+ mRecyclerView.layout(0, 0, 50, 50);
+ }
+
+ @Test
+ public void testRequireScroll() {
+ mDelegate.startListening();
+ verify(mRequireScrollMixin).notifyScrollabilityChange(true);
+ }
+
+ @Test
+ public void testScrolledToBottom() {
+ mDelegate.startListening();
+ verify(mRequireScrollMixin).notifyScrollabilityChange(true);
+
+ doReturn(20).when(mRecyclerView).computeVerticalScrollOffset();
+ mListenerCaptor.getValue().onScrolled(mRecyclerView, 0, 20);
+
+ verify(mRequireScrollMixin).notifyScrollabilityChange(false);
+ }
+
+ @Test
+ public void testClickScrollButton() {
+ mDelegate.pageScrollDown();
+ verify(mRecyclerView).smoothScrollBy(anyInt(), eq(50));
+ }
}
diff --git a/library/rules.gradle b/library/rules.gradle
index 9baa390..4e815ce 100644
--- a/library/rules.gradle
+++ b/library/rules.gradle
@@ -26,7 +26,7 @@ android {
// Provides backwards compatibility for Gingerbread or above, using support libraries.
gingerbreadCompat {
dimension 'compat'
- minSdkVersion 9
+ minSdkVersion 14
}
}
diff --git a/library/self.gradle b/library/self.gradle
index a4bff4e..f649581 100644
--- a/library/self.gradle
+++ b/library/self.gradle
@@ -25,8 +25,8 @@ android.sourceSets {
res.srcDirs = ['test/instrumentation/res']
dependencies {
- androidTestImplementation 'com.android.support.test:rules:1.0.0'
- androidTestImplementation 'com.android.support.test:runner:1.0.0'
+ androidTestImplementation 'com.android.support.test:rules:1.0.1'
+ androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.google.dexmaker:dexmaker:1.2'
androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestImplementation 'com.google.truth:truth:0.31'
@@ -51,8 +51,8 @@ android.sourceSets {
java.srcDirs = ['test/robotest/src']
dependencies {
- testImplementation 'org.robolectric:robolectric:3.6.1'
- testImplementation 'org.robolectric:shadows-framework:3.6.1'
+ testImplementation 'org.robolectric:robolectric:4.0-alpha-3'
+ testImplementation 'org.robolectric:shadows-framework:4.0-alpha-3'
testImplementation 'junit:junit:4.+'
testImplementation 'com.google.truth:truth:0.31'
testImplementation 'org.mockito:mockito-core:1.9.5'
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/TemplateLayoutTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/TemplateLayoutTest.java
index ddce677..a5026ee 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/TemplateLayoutTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/TemplateLayoutTest.java
@@ -23,16 +23,14 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.template.HeaderMixin;
import com.android.setupwizardlib.test.R;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,65 +39,64 @@ import org.junit.runner.RunWith;
@SmallTest
public class TemplateLayoutTest {
- private Context mContext;
+ private Context mContext;
- @Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getContext();
- }
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ }
- @Test
- public void testAddView() {
- TemplateLayout layout = new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content);
- TextView tv = new TextView(mContext);
- tv.setId(R.id.test_view_id);
- layout.addView(tv);
- View view = layout.findViewById(R.id.test_view_id);
- assertSame("The view added should be the same text view", tv, view);
- }
+ @Test
+ public void testAddView() {
+ TemplateLayout layout =
+ new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content);
+ TextView tv = new TextView(mContext);
+ tv.setId(R.id.test_view_id);
+ layout.addView(tv);
+ View view = layout.findViewById(R.id.test_view_id);
+ assertSame("The view added should be the same text view", tv, view);
+ }
- @Test
- public void testInflateFromXml() {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- TemplateLayout layout =
- (TemplateLayout) inflater.inflate(R.layout.test_template_layout, null);
- View content = layout.findViewById(R.id.test_content);
- assertTrue("@id/test_content should be a TextView", content instanceof TextView);
- }
+ @Test
+ public void testInflateFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ TemplateLayout layout = (TemplateLayout) inflater.inflate(R.layout.test_template_layout, null);
+ View content = layout.findViewById(R.id.test_content);
+ assertTrue("@id/test_content should be a TextView", content instanceof TextView);
+ }
- @Test
- public void testTemplate() {
- TemplateLayout layout = new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content);
- View templateView = layout.findViewById(R.id.test_template_view);
- assertNotNull("@id/test_template_view should exist in template", templateView);
+ @Test
+ public void testTemplate() {
+ TemplateLayout layout =
+ new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content);
+ View templateView = layout.findViewById(R.id.test_template_view);
+ assertNotNull("@id/test_template_view should exist in template", templateView);
- TextView tv = new TextView(mContext);
- tv.setId(R.id.test_view_id);
- layout.addView(tv);
+ TextView tv = new TextView(mContext);
+ tv.setId(R.id.test_view_id);
+ layout.addView(tv);
- templateView = layout.findViewById(R.id.test_template_view);
- assertNotNull("@id/test_template_view should exist in template", templateView);
- View contentView = layout.findViewById(R.id.test_view_id);
- assertSame("The view added should be the same text view", tv, contentView);
- }
+ templateView = layout.findViewById(R.id.test_template_view);
+ assertNotNull("@id/test_template_view should exist in template", templateView);
+ View contentView = layout.findViewById(R.id.test_view_id);
+ assertSame("The view added should be the same text view", tv, contentView);
+ }
- @Test
- public void testNoTemplate() {
- try {
- new TemplateLayout(mContext, 0, 0);
- fail("Inflating TemplateLayout without template should throw exception");
- } catch (IllegalArgumentException e) {
- // Expected IllegalArgumentException
- }
+ @Test
+ public void testNoTemplate() {
+ try {
+ new TemplateLayout(mContext, 0, 0);
+ fail("Inflating TemplateLayout without template should throw exception");
+ } catch (IllegalArgumentException e) {
+ // Expected IllegalArgumentException
}
+ }
- @Test
- public void testGetMixin() {
- TemplateLayout layout = new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content);
- final HeaderMixin mixin = layout.getMixin(HeaderMixin.class);
- assertNull("getMixin for a mixin that doesn't exist should return null", mixin);
- }
+ @Test
+ public void testGetMixin() {
+ TemplateLayout layout =
+ new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content);
+ final HeaderMixin mixin = layout.getMixin(HeaderMixin.class);
+ assertNull("getMixin for a mixin that doesn't exist should return null", mixin);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/template/ButtonFooterMixinTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/template/ButtonFooterMixinTest.java
index 08f5958..971211b 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/template/ButtonFooterMixinTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/template/ButtonFooterMixinTest.java
@@ -24,9 +24,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.annotation.IdRes;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
@@ -34,12 +32,11 @@ import android.view.ViewStub;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-
-import androidx.annotation.IdRes;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,125 +45,128 @@ import org.junit.runner.RunWith;
@SmallTest
public class ButtonFooterMixinTest {
- private Context mContext;
- private TemplateLayout mTemplateLayout;
-
- // The parent view to contain the view stub and views it inflates.
- private FrameLayout mStubParent;
- private ViewStub mFooterStub;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mTemplateLayout = spy(new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content));
-
- mFooterStub = new ViewStub(mContext, R.layout.suw_glif_footer_button_bar);
- mStubParent = new FrameLayout(mContext);
- mStubParent.addView(mFooterStub);
- doReturn(mFooterStub).when(mTemplateLayout).findManagedViewById(eq(R.id.suw_layout_footer));
- }
-
- @Test
- public void testAddButton() {
- ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
- final Button button = mixin.addButton("foobar", R.style.SuwGlifButton_Primary);
-
- assertNotNull(button);
- @IdRes final int id = 12345;
- button.setId(id);
- assertNotNull(mStubParent.findViewById(id));
-
- assertEquals("foobar", button.getText());
-
- // Make sure the style is applied by checking the paddings
- assertEquals(dp2Px(16), button.getPaddingLeft());
- assertEquals(dp2Px(16), button.getPaddingRight());
- }
-
- @Test
- public void testAddButtonTextRes() {
- ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
- final Button button = mixin.addButton(R.string.suw_next_button_label,
- R.style.SuwGlifButton_Primary);
-
- assertNotNull(button);
- button.setTag("button");
- assertNotNull(mStubParent.findViewWithTag("button"));
-
- assertEquals("Next", button.getText());
-
- // Make sure the style is applied by checking the paddings
- assertEquals(dp2Px(16), button.getPaddingLeft());
- assertEquals(dp2Px(16), button.getPaddingRight());
- }
-
- @Test
- public void testAddSpace() {
- ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
- mixin.addButton("foo", R.style.SuwGlifButton_Secondary);
- final View space = mixin.addSpace();
- mixin.addButton("bar", R.style.SuwGlifButton_Primary);
-
- space.setTag("space");
- assertNotNull(mStubParent.findViewWithTag("space"));
- assertEquals("Space should have weight of 1",
- 1f, ((LinearLayout.LayoutParams) space.getLayoutParams()).weight, 0.001);
- }
-
- @Test
- public void testRemoveButton() {
- ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
- final Button fooButton = mixin.addButton("foo", R.style.SuwGlifButton_Secondary);
- final Button barButton = mixin.addButton("bar", R.style.SuwGlifButton_Secondary);
-
- fooButton.setTag("foo");
- barButton.setTag("bar");
- assertNotNull("Foo button should exist", mStubParent.findViewWithTag("foo"));
- assertNotNull("Bar button should exist", mStubParent.findViewWithTag("bar"));
-
- mixin.removeButton(fooButton);
-
- assertNull("Foo button should be removed", mStubParent.findViewWithTag("foo"));
- assertNotNull("Bar button should not be removed", mStubParent.findViewWithTag("bar"));
- }
-
- @Test
- public void testRemoveSpace() {
- ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
- final Button fooButton = mixin.addButton("foo", R.style.SuwGlifButton_Secondary);
- final View space = mixin.addSpace();
-
- fooButton.setTag("foo");
- space.setTag("space");
- assertNotNull("Foo button should exist", mStubParent.findViewWithTag("foo"));
- assertNotNull("space should exist", mStubParent.findViewWithTag("space"));
-
- mixin.removeSpace(space);
-
- assertNotNull("Foo button should not be removed", mStubParent.findViewWithTag("foo"));
- assertNull("Space should be removed", mStubParent.findViewWithTag("space"));
- }
-
- @Test
- public void testRemoveAllViews() {
- ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
- final Button fooButton = mixin.addButton("foo", R.style.SuwGlifButton_Secondary);
- final View space = mixin.addSpace();
-
- fooButton.setTag("foo");
- space.setTag("space");
- assertNotNull("Foo button should exist", mStubParent.findViewWithTag("foo"));
- assertNotNull("space should exist", mStubParent.findViewWithTag("space"));
-
- mixin.removeAllViews();
-
- assertNull("Foo button should be removed", mStubParent.findViewWithTag("foo"));
- assertNull("Space should be removed", mStubParent.findViewWithTag("space"));
- }
-
- private int dp2Px(float dp) {
- DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
- return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics);
- }
+ private Context mContext;
+ private TemplateLayout mTemplateLayout;
+
+ // The parent view to contain the view stub and views it inflates.
+ private FrameLayout mStubParent;
+ private ViewStub mFooterStub;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mTemplateLayout =
+ spy(new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content));
+
+ mFooterStub = new ViewStub(mContext, R.layout.suw_glif_footer_button_bar);
+ mStubParent = new FrameLayout(mContext);
+ mStubParent.addView(mFooterStub);
+ doReturn(mFooterStub).when(mTemplateLayout).findManagedViewById(eq(R.id.suw_layout_footer));
+ }
+
+ @Test
+ public void testAddButton() {
+ ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
+ final Button button = mixin.addButton("foobar", R.style.SuwGlifButton_Primary);
+
+ assertNotNull(button);
+ @IdRes final int id = 12345;
+ button.setId(id);
+ assertNotNull(mStubParent.findViewById(id));
+
+ assertEquals("foobar", button.getText());
+
+ // Make sure the style is applied by checking the paddings
+ assertEquals(dp2Px(16), button.getPaddingLeft());
+ assertEquals(dp2Px(16), button.getPaddingRight());
+ }
+
+ @Test
+ public void testAddButtonTextRes() {
+ ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
+ final Button button =
+ mixin.addButton(R.string.suw_next_button_label, R.style.SuwGlifButton_Primary);
+
+ assertNotNull(button);
+ button.setTag("button");
+ assertNotNull(mStubParent.findViewWithTag("button"));
+
+ assertEquals("Next", button.getText());
+
+ // Make sure the style is applied by checking the paddings
+ assertEquals(dp2Px(16), button.getPaddingLeft());
+ assertEquals(dp2Px(16), button.getPaddingRight());
+ }
+
+ @Test
+ public void testAddSpace() {
+ ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
+ mixin.addButton("foo", R.style.SuwGlifButton_Secondary);
+ final View space = mixin.addSpace();
+ mixin.addButton("bar", R.style.SuwGlifButton_Primary);
+
+ space.setTag("space");
+ assertNotNull(mStubParent.findViewWithTag("space"));
+ assertEquals(
+ "Space should have weight of 1",
+ 1f,
+ ((LinearLayout.LayoutParams) space.getLayoutParams()).weight,
+ 0.001);
+ }
+
+ @Test
+ public void testRemoveButton() {
+ ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
+ final Button fooButton = mixin.addButton("foo", R.style.SuwGlifButton_Secondary);
+ final Button barButton = mixin.addButton("bar", R.style.SuwGlifButton_Secondary);
+
+ fooButton.setTag("foo");
+ barButton.setTag("bar");
+ assertNotNull("Foo button should exist", mStubParent.findViewWithTag("foo"));
+ assertNotNull("Bar button should exist", mStubParent.findViewWithTag("bar"));
+
+ mixin.removeButton(fooButton);
+
+ assertNull("Foo button should be removed", mStubParent.findViewWithTag("foo"));
+ assertNotNull("Bar button should not be removed", mStubParent.findViewWithTag("bar"));
+ }
+
+ @Test
+ public void testRemoveSpace() {
+ ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
+ final Button fooButton = mixin.addButton("foo", R.style.SuwGlifButton_Secondary);
+ final View space = mixin.addSpace();
+
+ fooButton.setTag("foo");
+ space.setTag("space");
+ assertNotNull("Foo button should exist", mStubParent.findViewWithTag("foo"));
+ assertNotNull("space should exist", mStubParent.findViewWithTag("space"));
+
+ mixin.removeSpace(space);
+
+ assertNotNull("Foo button should not be removed", mStubParent.findViewWithTag("foo"));
+ assertNull("Space should be removed", mStubParent.findViewWithTag("space"));
+ }
+
+ @Test
+ public void testRemoveAllViews() {
+ ButtonFooterMixin mixin = new ButtonFooterMixin(mTemplateLayout);
+ final Button fooButton = mixin.addButton("foo", R.style.SuwGlifButton_Secondary);
+ final View space = mixin.addSpace();
+
+ fooButton.setTag("foo");
+ space.setTag("space");
+ assertNotNull("Foo button should exist", mStubParent.findViewWithTag("foo"));
+ assertNotNull("space should exist", mStubParent.findViewWithTag("space"));
+
+ mixin.removeAllViews();
+
+ assertNull("Foo button should be removed", mStubParent.findViewWithTag("foo"));
+ assertNull("Space should be removed", mStubParent.findViewWithTag("space"));
+ }
+
+ private int dp2Px(float dp) {
+ DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/template/ColoredHeaderMixinTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/template/ColoredHeaderMixinTest.java
index 1c86af1..3ea8f6e 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/template/ColoredHeaderMixinTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/template/ColoredHeaderMixinTest.java
@@ -25,67 +25,62 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.XmlResourceParser;
import android.graphics.Color;
+import android.util.Xml;
+import android.widget.TextView;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.util.Xml;
-import android.widget.TextView;
-
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
-
+import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.IOException;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ColoredHeaderMixinTest {
- private Context mContext;
- private TemplateLayout mTemplateLayout;
- private TextView mHeaderTextView;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mTemplateLayout = spy(new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content));
-
- mHeaderTextView = new TextView(mContext);
- doReturn(mHeaderTextView).when(mTemplateLayout)
- .findManagedViewById(eq(R.id.suw_layout_title));
+ private Context mContext;
+ private TemplateLayout mTemplateLayout;
+ private TextView mHeaderTextView;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mTemplateLayout =
+ spy(new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content));
+
+ mHeaderTextView = new TextView(mContext);
+ doReturn(mHeaderTextView).when(mTemplateLayout).findManagedViewById(eq(R.id.suw_layout_title));
+ }
+
+ @Test
+ public void testSetColor() {
+ ColoredHeaderMixin mixin = new ColoredHeaderMixin(mTemplateLayout, null, 0);
+ mixin.setColor(ColorStateList.valueOf(Color.MAGENTA));
+
+ assertEquals(ColorStateList.valueOf(Color.MAGENTA), mHeaderTextView.getTextColors());
+ }
+
+ @Test
+ public void testGetColor() {
+ ColoredHeaderMixin mixin = new ColoredHeaderMixin(mTemplateLayout, null, 0);
+ mHeaderTextView.setTextColor(ColorStateList.valueOf(Color.GREEN));
+
+ assertEquals(ColorStateList.valueOf(Color.GREEN), mixin.getColor());
+ }
+
+ @SuppressWarnings("ResourceType") // Needed to create attribute set from layout XML.
+ @Test
+ public void testSetColorFromXml() throws IOException, XmlPullParserException {
+ final XmlResourceParser parser = mContext.getResources().getXml(R.layout.test_mixin_attributes);
+ while (!TemplateLayout.class.getName().equals(parser.getName())) {
+ parser.next();
}
+ new ColoredHeaderMixin(mTemplateLayout, Xml.asAttributeSet(parser), 0);
- @Test
- public void testSetColor() {
- ColoredHeaderMixin mixin = new ColoredHeaderMixin(mTemplateLayout, null, 0);
- mixin.setColor(ColorStateList.valueOf(Color.MAGENTA));
-
- assertEquals(ColorStateList.valueOf(Color.MAGENTA), mHeaderTextView.getTextColors());
- }
-
- @Test
- public void testGetColor() {
- ColoredHeaderMixin mixin = new ColoredHeaderMixin(mTemplateLayout, null, 0);
- mHeaderTextView.setTextColor(ColorStateList.valueOf(Color.GREEN));
-
- assertEquals(ColorStateList.valueOf(Color.GREEN), mixin.getColor());
- }
-
- @SuppressWarnings("ResourceType") // Needed to create attribute set from layout XML.
- @Test
- public void testSetColorFromXml() throws IOException, XmlPullParserException {
- final XmlResourceParser parser =
- mContext.getResources().getXml(R.layout.test_mixin_attributes);
- while (!TemplateLayout.class.getName().equals(parser.getName())) {
- parser.next();
- }
- new ColoredHeaderMixin(mTemplateLayout, Xml.asAttributeSet(parser), 0);
-
- assertEquals(ColorStateList.valueOf(Color.RED), mHeaderTextView.getTextColors());
- }
+ assertEquals(ColorStateList.valueOf(Color.RED), mHeaderTextView.getTextColors());
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/template/HeaderMixinTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/template/HeaderMixinTest.java
index a1b4b59..211f95f 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/template/HeaderMixinTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/template/HeaderMixinTest.java
@@ -25,82 +25,77 @@ import static org.mockito.Mockito.spy;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.XmlResourceParser;
+import android.util.Xml;
+import android.widget.TextView;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.util.Xml;
-import android.widget.TextView;
-
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
-
+import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.IOException;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class HeaderMixinTest {
- private Context mContext;
- private TemplateLayout mTemplateLayout;
- private TextView mHeaderTextView;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mTemplateLayout = spy(new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content));
-
- mHeaderTextView = new TextView(mContext);
- doReturn(mHeaderTextView).when(mTemplateLayout)
- .findManagedViewById(eq(R.id.suw_layout_title));
+ private Context mContext;
+ private TemplateLayout mTemplateLayout;
+ private TextView mHeaderTextView;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mTemplateLayout =
+ spy(new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content));
+
+ mHeaderTextView = new TextView(mContext);
+ doReturn(mHeaderTextView).when(mTemplateLayout).findManagedViewById(eq(R.id.suw_layout_title));
+ }
+
+ @Test
+ public void testGetTextView() {
+ HeaderMixin mixin = new HeaderMixin(mTemplateLayout, null, 0);
+ assertSame(mHeaderTextView, mixin.getTextView());
+ }
+
+ @Test
+ public void testSetTextId() {
+ HeaderMixin mixin = new HeaderMixin(mTemplateLayout, null, 0);
+ mixin.setText(R.string.suw_next_button_label);
+
+ assertEquals("Next", mHeaderTextView.getText());
+ }
+
+ @Test
+ public void testSetText() {
+ HeaderMixin mixin = new HeaderMixin(mTemplateLayout, null, 0);
+ mixin.setText("Foobar");
+
+ assertEquals("Foobar", mHeaderTextView.getText());
+ }
+
+ @SuppressLint("SetTextI18n") // It's OK, this is a test
+ @Test
+ public void testGetText() {
+ mHeaderTextView.setText("Lorem ipsum");
+
+ HeaderMixin mixin = new HeaderMixin(mTemplateLayout, null, 0);
+ assertEquals("Lorem ipsum", mixin.getText());
+ }
+
+ @SuppressWarnings("ResourceType") // Needed to create attribute set from layout XML.
+ @Test
+ public void testSetTextFromXml() throws IOException, XmlPullParserException {
+ final XmlResourceParser parser = mContext.getResources().getXml(R.layout.test_mixin_attributes);
+ while (!TemplateLayout.class.getName().equals(parser.getName())) {
+ parser.next();
}
+ new HeaderMixin(mTemplateLayout, Xml.asAttributeSet(parser), 0);
- @Test
- public void testGetTextView() {
- HeaderMixin mixin = new HeaderMixin(mTemplateLayout, null, 0);
- assertSame(mHeaderTextView, mixin.getTextView());
- }
-
- @Test
- public void testSetTextId() {
- HeaderMixin mixin = new HeaderMixin(mTemplateLayout, null, 0);
- mixin.setText(R.string.suw_next_button_label);
-
- assertEquals("Next", mHeaderTextView.getText());
- }
-
- @Test
- public void testSetText() {
- HeaderMixin mixin = new HeaderMixin(mTemplateLayout, null, 0);
- mixin.setText("Foobar");
-
- assertEquals("Foobar", mHeaderTextView.getText());
- }
-
- @SuppressLint("SetTextI18n") // It's OK, this is a test
- @Test
- public void testGetText() {
- mHeaderTextView.setText("Lorem ipsum");
-
- HeaderMixin mixin = new HeaderMixin(mTemplateLayout, null, 0);
- assertEquals("Lorem ipsum", mixin.getText());
- }
-
- @SuppressWarnings("ResourceType") // Needed to create attribute set from layout XML.
- @Test
- public void testSetTextFromXml() throws IOException, XmlPullParserException {
- final XmlResourceParser parser =
- mContext.getResources().getXml(R.layout.test_mixin_attributes);
- while (!TemplateLayout.class.getName().equals(parser.getName())) {
- parser.next();
- }
- new HeaderMixin(mTemplateLayout, Xml.asAttributeSet(parser), 0);
-
- assertEquals("lorem ipsum", mHeaderTextView.getText());
- }
+ assertEquals("lorem ipsum", mHeaderTextView.getText());
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/template/IconMixinTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/template/IconMixinTest.java
index 5a36f4a..001fe33 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/template/IconMixinTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/template/IconMixinTest.java
@@ -17,7 +17,6 @@
package com.android.setupwizardlib.template;
import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.mockito.Matchers.eq;
@@ -30,115 +29,111 @@ import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.util.Xml;
import android.view.View;
import android.widget.ImageView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
-
+import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.IOException;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class IconMixinTest {
- private Context mContext;
- private TemplateLayout mTemplateLayout;
- private ImageView mIconView;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
- mTemplateLayout = spy(new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content));
-
- mIconView = new ImageView(mContext);
- doReturn(mIconView).when(mTemplateLayout).findManagedViewById(eq(R.id.suw_layout_icon));
- }
-
- @Test
- public void testGetIconView() {
- IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
- assertSame(mIconView, mixin.getView());
- }
-
- @Test
- public void testSetIcon() {
- final ColorDrawable drawable = new ColorDrawable(Color.CYAN);
- IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
- mixin.setIcon(drawable);
-
- assertSame(drawable, mIconView.getDrawable());
- assertEquals(View.VISIBLE, mIconView.getVisibility());
- }
-
- @Test
- public void setIcon_resourceId_shouldSetIcon() {
- int icon = android.R.drawable.ic_menu_add;
- IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
- mixin.setIcon(icon);
-
- Drawable drawable = mIconView.getDrawable();
- assertThat(drawable).isInstanceOf(BitmapDrawable.class);
- assertEquals(View.VISIBLE, mIconView.getVisibility());
- }
-
- @Test
- public void setIcon_shouldSetVisibilityToGone_whenIconIsNull() {
- IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
- mixin.setIcon(null);
-
- assertEquals(View.GONE, mIconView.getVisibility());
- }
-
- @Test
- public void testGetIcon() {
- final ColorDrawable drawable = new ColorDrawable(Color.BLUE);
- mIconView.setImageDrawable(drawable);
-
- IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
- assertSame(drawable, mixin.getIcon());
- }
-
- @SuppressWarnings("ResourceType") // Needed to create attribute set from layout XML.
- @Test
- public void testSetIconFromXml() throws IOException, XmlPullParserException {
- final XmlResourceParser parser =
- mContext.getResources().getXml(R.layout.test_mixin_attributes);
- while (!TemplateLayout.class.getName().equals(parser.getName())) {
- parser.next();
- }
- new IconMixin(mTemplateLayout, Xml.asAttributeSet(parser), 0);
-
- // Check that the bitmaps themselves are equal because BitmapDrawable does not implement
- // equals()
- final BitmapDrawable expected = (BitmapDrawable) mContext.getResources()
- .getDrawable(android.R.drawable.ic_menu_add);
- final BitmapDrawable actual = (BitmapDrawable) mIconView.getDrawable();
- assertEquals(expected.getBitmap(), actual.getBitmap());
- assertEquals(View.VISIBLE, mIconView.getVisibility());
- }
-
- @Test
- public void setContentDescription_shouldSetContentDescriptionOnIconView() {
- IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
- mixin.setContentDescription("hello world");
- assertThat(mIconView.getContentDescription()).isEqualTo("hello world");
- }
-
- @Test
- public void getContentDescription_shouldReturnContentDescriptionFromView() {
- IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
- mIconView.setContentDescription("aloha");
- assertThat(mixin.getContentDescription()).isEqualTo("aloha");
+ private Context mContext;
+ private TemplateLayout mTemplateLayout;
+ private ImageView mIconView;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ mTemplateLayout =
+ spy(new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content));
+
+ mIconView = new ImageView(mContext);
+ doReturn(mIconView).when(mTemplateLayout).findManagedViewById(eq(R.id.suw_layout_icon));
+ }
+
+ @Test
+ public void testGetIconView() {
+ IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
+ assertSame(mIconView, mixin.getView());
+ }
+
+ @Test
+ public void testSetIcon() {
+ final ColorDrawable drawable = new ColorDrawable(Color.CYAN);
+ IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
+ mixin.setIcon(drawable);
+
+ assertSame(drawable, mIconView.getDrawable());
+ assertEquals(View.VISIBLE, mIconView.getVisibility());
+ }
+
+ @Test
+ public void setIcon_resourceId_shouldSetIcon() {
+ int icon = android.R.drawable.ic_menu_add;
+ IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
+ mixin.setIcon(icon);
+
+ Drawable drawable = mIconView.getDrawable();
+ assertThat(drawable).isInstanceOf(BitmapDrawable.class);
+ assertEquals(View.VISIBLE, mIconView.getVisibility());
+ }
+
+ @Test
+ public void setIcon_shouldSetVisibilityToGone_whenIconIsNull() {
+ IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
+ mixin.setIcon(null);
+
+ assertEquals(View.GONE, mIconView.getVisibility());
+ }
+
+ @Test
+ public void testGetIcon() {
+ final ColorDrawable drawable = new ColorDrawable(Color.BLUE);
+ mIconView.setImageDrawable(drawable);
+
+ IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
+ assertSame(drawable, mixin.getIcon());
+ }
+
+ @SuppressWarnings("ResourceType") // Needed to create attribute set from layout XML.
+ @Test
+ public void testSetIconFromXml() throws IOException, XmlPullParserException {
+ final XmlResourceParser parser = mContext.getResources().getXml(R.layout.test_mixin_attributes);
+ while (!TemplateLayout.class.getName().equals(parser.getName())) {
+ parser.next();
}
+ new IconMixin(mTemplateLayout, Xml.asAttributeSet(parser), 0);
+
+ // Check that the bitmaps themselves are equal because BitmapDrawable does not implement
+ // equals()
+ final BitmapDrawable expected =
+ (BitmapDrawable) mContext.getResources().getDrawable(android.R.drawable.ic_menu_add);
+ final BitmapDrawable actual = (BitmapDrawable) mIconView.getDrawable();
+ assertEquals(expected.getBitmap(), actual.getBitmap());
+ assertEquals(View.VISIBLE, mIconView.getVisibility());
+ }
+
+ @Test
+ public void setContentDescription_shouldSetContentDescriptionOnIconView() {
+ IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
+ mixin.setContentDescription("hello world");
+ assertThat(mIconView.getContentDescription()).isEqualTo("hello world");
+ }
+
+ @Test
+ public void getContentDescription_shouldReturnContentDescriptionFromView() {
+ IconMixin mixin = new IconMixin(mTemplateLayout, null, 0);
+ mIconView.setContentDescription("aloha");
+ assertThat(mixin.getContentDescription()).isEqualTo("aloha");
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/template/ListMixinTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/template/ListMixinTest.java
index 30d68f1..e73e2bc 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/template/ListMixinTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/template/ListMixinTest.java
@@ -32,16 +32,14 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.ListView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,140 +50,138 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class ListMixinTest {
- private Context mContext;
- private TemplateLayout mTemplateLayout;
+ private Context mContext;
+ private TemplateLayout mTemplateLayout;
- private ListView mListView;
+ private ListView mListView;
- @Mock
- private ListAdapter mAdapter;
+ @Mock private ListAdapter mAdapter;
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getTargetContext();
- mTemplateLayout = spy(new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content));
+ mContext = InstrumentationRegistry.getTargetContext();
+ mTemplateLayout =
+ spy(new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content));
- mListView = mock(ListView.class, delegatesTo(new ListView(mContext)));
- doReturn(1).when(mAdapter).getViewTypeCount();
+ mListView = mock(ListView.class, delegatesTo(new ListView(mContext)));
+ doReturn(1).when(mAdapter).getViewTypeCount();
- doReturn(mListView).when(mTemplateLayout)
- .findManagedViewById(eq(android.R.id.list));
- doReturn(true).when(mTemplateLayout).isLayoutDirectionResolved();
- }
+ doReturn(mListView).when(mTemplateLayout).findManagedViewById(eq(android.R.id.list));
+ doReturn(true).when(mTemplateLayout).isLayoutDirectionResolved();
+ }
- @Test
- public void testGetListView() {
- ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
- assertSame(mListView, mixin.getListView());
- }
+ @Test
+ public void testGetListView() {
+ ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
+ assertSame(mListView, mixin.getListView());
+ }
- @Test
- public void testGetAdapter() {
- mListView.setAdapter(mAdapter);
+ @Test
+ public void testGetAdapter() {
+ mListView.setAdapter(mAdapter);
- ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
- assertSame(mAdapter, mixin.getAdapter());
- }
+ ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
+ assertSame(mAdapter, mixin.getAdapter());
+ }
- @Test
- public void testSetAdapter() {
- assertNull(mListView.getAdapter());
+ @Test
+ public void testSetAdapter() {
+ assertNull(mListView.getAdapter());
- ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
- mixin.setAdapter(mAdapter);
+ ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
+ mixin.setAdapter(mAdapter);
- assertSame(mAdapter, mListView.getAdapter());
- }
+ assertSame(mAdapter, mListView.getAdapter());
+ }
- @Test
- public void testDividerInsetLegacy() {
- ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
- mixin.setDividerInset(123);
+ @Test
+ public void testDividerInsetLegacy() {
+ ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
+ mixin.setDividerInset(123);
- assertEquals(123, mixin.getDividerInset());
+ assertEquals(123, mixin.getDividerInset());
- final Drawable divider = mListView.getDivider();
- InsetDrawable insetDrawable = (InsetDrawable) divider;
- Rect rect = new Rect();
- insetDrawable.getPadding(rect);
+ final Drawable divider = mListView.getDivider();
+ InsetDrawable insetDrawable = (InsetDrawable) divider;
+ Rect rect = new Rect();
+ insetDrawable.getPadding(rect);
- assertEquals(new Rect(123, 0, 0, 0), rect);
- }
+ assertEquals(new Rect(123, 0, 0, 0), rect);
+ }
- @Test
- public void testDividerInsets() {
- ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
- mixin.setDividerInsets(123, 456);
+ @Test
+ public void testDividerInsets() {
+ ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
+ mixin.setDividerInsets(123, 456);
- assertEquals(123, mixin.getDividerInsetStart());
- assertEquals(456, mixin.getDividerInsetEnd());
+ assertEquals(123, mixin.getDividerInsetStart());
+ assertEquals(456, mixin.getDividerInsetEnd());
- final Drawable divider = mListView.getDivider();
- InsetDrawable insetDrawable = (InsetDrawable) divider;
- Rect rect = new Rect();
- insetDrawable.getPadding(rect);
+ final Drawable divider = mListView.getDivider();
+ InsetDrawable insetDrawable = (InsetDrawable) divider;
+ Rect rect = new Rect();
+ insetDrawable.getPadding(rect);
- assertEquals(new Rect(123, 0, 456, 0), rect);
- }
+ assertEquals(new Rect(123, 0, 456, 0), rect);
+ }
- @Test
- public void testDividerInsetLegacyRtl() {
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
- doReturn(View.LAYOUT_DIRECTION_RTL).when(mTemplateLayout).getLayoutDirection();
+ @Test
+ public void testDividerInsetLegacyRtl() {
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ doReturn(View.LAYOUT_DIRECTION_RTL).when(mTemplateLayout).getLayoutDirection();
- ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
- mixin.setDividerInset(123);
+ ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
+ mixin.setDividerInset(123);
- assertEquals(123, mixin.getDividerInset());
+ assertEquals(123, mixin.getDividerInset());
- final Drawable divider = mListView.getDivider();
- InsetDrawable insetDrawable = (InsetDrawable) divider;
- Rect rect = new Rect();
- insetDrawable.getPadding(rect);
+ final Drawable divider = mListView.getDivider();
+ InsetDrawable insetDrawable = (InsetDrawable) divider;
+ Rect rect = new Rect();
+ insetDrawable.getPadding(rect);
- assertEquals(new Rect(0, 0, 123, 0), rect);
- }
- // else the test passes
+ assertEquals(new Rect(0, 0, 123, 0), rect);
}
+ // else the test passes
+ }
- @Test
- public void testDividerInsetsRtl() {
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
- doReturn(View.LAYOUT_DIRECTION_RTL).when(mTemplateLayout).getLayoutDirection();
+ @Test
+ public void testDividerInsetsRtl() {
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ doReturn(View.LAYOUT_DIRECTION_RTL).when(mTemplateLayout).getLayoutDirection();
- ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
- mixin.setDividerInsets(123, 456);
+ ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
+ mixin.setDividerInsets(123, 456);
- assertEquals(123, mixin.getDividerInsetStart());
- assertEquals(456, mixin.getDividerInsetEnd());
+ assertEquals(123, mixin.getDividerInsetStart());
+ assertEquals(456, mixin.getDividerInsetEnd());
- final Drawable divider = mListView.getDivider();
- InsetDrawable insetDrawable = (InsetDrawable) divider;
- Rect rect = new Rect();
- insetDrawable.getPadding(rect);
+ final Drawable divider = mListView.getDivider();
+ InsetDrawable insetDrawable = (InsetDrawable) divider;
+ Rect rect = new Rect();
+ insetDrawable.getPadding(rect);
- assertEquals(new Rect(456, 0, 123, 0), rect);
- }
- // else the test passes
+ assertEquals(new Rect(456, 0, 123, 0), rect);
}
+ // else the test passes
+ }
- @Test
- public void testNoList() {
- doReturn(null).when(mTemplateLayout).findManagedViewById(eq(android.R.id.list));
+ @Test
+ public void testNoList() {
+ doReturn(null).when(mTemplateLayout).findManagedViewById(eq(android.R.id.list));
- ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
+ ListMixin mixin = new ListMixin(mTemplateLayout, null, 0);
- mixin.setAdapter(mAdapter);
- mixin.setDividerInset(123);
+ mixin.setAdapter(mAdapter);
+ mixin.setDividerInset(123);
- assertNull(mixin.getListView());
- assertNull(mixin.getAdapter());
- mixin.getDividerInset(); // Test that it doesn't crash. The return value is not significant.
- assertNull(mixin.getDivider());
+ assertNull(mixin.getListView());
+ assertNull(mixin.getAdapter());
+ mixin.getDividerInset(); // Test that it doesn't crash. The return value is not significant.
+ assertNull(mixin.getDivider());
- verifyNoMoreInteractions(mListView);
- }
+ verifyNoMoreInteractions(mListView);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/template/NavigationBarMixinTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/template/NavigationBarMixinTest.java
index aca6084..1e2aff3 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/template/NavigationBarMixinTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/template/NavigationBarMixinTest.java
@@ -29,12 +29,10 @@ import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
import com.android.setupwizardlib.view.NavigationBar;
import com.android.setupwizardlib.view.NavigationBar.NavigationBarListener;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,56 +41,57 @@ import org.junit.runner.RunWith;
@SmallTest
public class NavigationBarMixinTest {
- private Context mContext;
- private TemplateLayout mTemplateLayout;
- private NavigationBar mNavigationBar;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
- mTemplateLayout = spy(new TemplateLayout(mContext, R.layout.test_template,
- R.id.suw_layout_content));
-
- mNavigationBar = new NavigationBar(mContext);
- doReturn(mNavigationBar).when(mTemplateLayout)
- .findManagedViewById(eq(R.id.suw_layout_navigation_bar));
- }
-
- @Test
- public void testGetNavigationBar() {
- NavigationBarMixin mixin = new NavigationBarMixin(mTemplateLayout);
- assertSame(mNavigationBar, mixin.getNavigationBar());
- }
-
- @Test
- public void testSetNextButtonText() {
- NavigationBarMixin mixin = new NavigationBarMixin(mTemplateLayout);
- mixin.setNextButtonText(R.string.suw_more_button_label);
- assertEquals("More", mNavigationBar.getNextButton().getText());
-
- mixin.setNextButtonText("Foobar");
- assertEquals("Foobar", mNavigationBar.getNextButton().getText());
- }
-
- @SuppressLint("SetTextI18n") // It's OK, this is just a test
- @Test
- public void testGetNextButtonText() {
- mNavigationBar.getNextButton().setText("lorem ipsum");
-
- NavigationBarMixin mixin = new NavigationBarMixin(mTemplateLayout);
- assertSame("lorem ipsum", mixin.getNextButtonText());
- }
-
- @Test
- public void testSetNavigationBarListener() {
- final NavigationBarListener listener = mock(NavigationBarListener.class);
- NavigationBarMixin mixin = new NavigationBarMixin(mTemplateLayout);
- mixin.setNavigationBarListener(listener);
-
- mNavigationBar.getNextButton().performClick();
- verify(listener).onNavigateNext();
-
- mNavigationBar.getBackButton().performClick();
- verify(listener).onNavigateBack();
- }
+ private Context mContext;
+ private TemplateLayout mTemplateLayout;
+ private NavigationBar mNavigationBar;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ mTemplateLayout =
+ spy(new TemplateLayout(mContext, R.layout.test_template, R.id.suw_layout_content));
+
+ mNavigationBar = new NavigationBar(mContext);
+ doReturn(mNavigationBar)
+ .when(mTemplateLayout)
+ .findManagedViewById(eq(R.id.suw_layout_navigation_bar));
+ }
+
+ @Test
+ public void testGetNavigationBar() {
+ NavigationBarMixin mixin = new NavigationBarMixin(mTemplateLayout);
+ assertSame(mNavigationBar, mixin.getNavigationBar());
+ }
+
+ @Test
+ public void testSetNextButtonText() {
+ NavigationBarMixin mixin = new NavigationBarMixin(mTemplateLayout);
+ mixin.setNextButtonText(R.string.suw_more_button_label);
+ assertEquals("More", mNavigationBar.getNextButton().getText());
+
+ mixin.setNextButtonText("Foobar");
+ assertEquals("Foobar", mNavigationBar.getNextButton().getText());
+ }
+
+ @SuppressLint("SetTextI18n") // It's OK, this is just a test
+ @Test
+ public void testGetNextButtonText() {
+ mNavigationBar.getNextButton().setText("lorem ipsum");
+
+ NavigationBarMixin mixin = new NavigationBarMixin(mTemplateLayout);
+ assertSame("lorem ipsum", mixin.getNextButtonText());
+ }
+
+ @Test
+ public void testSetNavigationBarListener() {
+ final NavigationBarListener listener = mock(NavigationBarListener.class);
+ NavigationBarMixin mixin = new NavigationBarMixin(mTemplateLayout);
+ mixin.setNavigationBarListener(listener);
+
+ mNavigationBar.getNextButton().performClick();
+ verify(listener).onNavigateNext();
+
+ mNavigationBar.getBackButton().performClick();
+ verify(listener).onNavigateBack();
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/template/ProgressBarMixinTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/template/ProgressBarMixinTest.java
index 5b2fb50..78ebe1e 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/template/ProgressBarMixinTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/template/ProgressBarMixinTest.java
@@ -29,16 +29,14 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.ProgressBar;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,111 +45,107 @@ import org.junit.runner.RunWith;
@SmallTest
public class ProgressBarMixinTest {
- private TemplateLayout mTemplateLayout;
-
- @Before
- public void setUp() {
- Context context = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeMaterial_Light);
- mTemplateLayout = new TemplateLayout(
- context,
- R.layout.test_progress_bar_template, R.id.suw_layout_content);
- }
-
- @Test
- public void testSetShown() {
- ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
- mixin.setShown(true);
-
- ProgressBar progressBar = (ProgressBar) mTemplateLayout.findViewById(
- R.id.suw_layout_progress);
- assertNotNull("Progress bar should be available after setting to shown", progressBar);
- assertEquals(View.VISIBLE, progressBar.getVisibility());
- }
-
- @Test
- public void testNotShown() {
- ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
- mixin.setShown(true);
- mixin.setShown(false);
-
- ProgressBar progressBar = (ProgressBar) mTemplateLayout.findViewById(
- R.id.suw_layout_progress);
- assertNotEquals(View.VISIBLE, progressBar.getVisibility());
+ private TemplateLayout mTemplateLayout;
+
+ @Before
+ public void setUp() {
+ Context context =
+ new ContextThemeWrapper(
+ InstrumentationRegistry.getContext(), R.style.SuwThemeMaterial_Light);
+ mTemplateLayout =
+ new TemplateLayout(context, R.layout.test_progress_bar_template, R.id.suw_layout_content);
+ }
+
+ @Test
+ public void testSetShown() {
+ ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
+ mixin.setShown(true);
+
+ ProgressBar progressBar = (ProgressBar) mTemplateLayout.findViewById(R.id.suw_layout_progress);
+ assertNotNull("Progress bar should be available after setting to shown", progressBar);
+ assertEquals(View.VISIBLE, progressBar.getVisibility());
+ }
+
+ @Test
+ public void testNotShown() {
+ ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
+ mixin.setShown(true);
+ mixin.setShown(false);
+
+ ProgressBar progressBar = (ProgressBar) mTemplateLayout.findViewById(R.id.suw_layout_progress);
+ assertNotEquals(View.VISIBLE, progressBar.getVisibility());
+ }
+
+ @Test
+ public void testIsShown() {
+ ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
+
+ mixin.setShown(true);
+ assertTrue(mixin.isShown());
+
+ mixin.setShown(false);
+ assertFalse(mixin.isShown());
+ }
+
+ @Test
+ public void testPeekProgressBar() {
+ ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
+ assertNull(
+ "PeekProgressBar should return null when stub not inflated yet", mixin.peekProgressBar());
+
+ mixin.setShown(true);
+ assertNotNull(
+ "PeekProgressBar should be available after setting to shown", mixin.peekProgressBar());
+ }
+
+ @Test
+ public void testSetColorBeforeSetShown() {
+ ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
+ mixin.setColor(ColorStateList.valueOf(Color.MAGENTA));
+
+ mixin.setShown(true);
+
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ ProgressBar progressBar =
+ (ProgressBar) mTemplateLayout.findViewById(R.id.suw_layout_progress);
+ assertEquals(ColorStateList.valueOf(Color.MAGENTA), progressBar.getIndeterminateTintList());
+ assertEquals(
+ ColorStateList.valueOf(Color.MAGENTA), progressBar.getProgressBackgroundTintList());
}
-
- @Test
- public void testIsShown() {
- ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
-
- mixin.setShown(true);
- assertTrue(mixin.isShown());
-
- mixin.setShown(false);
- assertFalse(mixin.isShown());
+ // this method is a no-op on versions < lollipop. Just check that it doesn't crash.
+ }
+
+ @Test
+ public void testSetColorAfterSetShown() {
+ ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
+ mixin.setShown(true);
+
+ mixin.setColor(ColorStateList.valueOf(Color.YELLOW));
+
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ ProgressBar progressBar =
+ (ProgressBar) mTemplateLayout.findViewById(R.id.suw_layout_progress);
+ assertEquals(ColorStateList.valueOf(Color.YELLOW), progressBar.getIndeterminateTintList());
+ assertEquals(
+ ColorStateList.valueOf(Color.YELLOW), progressBar.getProgressBackgroundTintList());
}
-
- @Test
- public void testPeekProgressBar() {
- ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
- assertNull("PeekProgressBar should return null when stub not inflated yet",
- mixin.peekProgressBar());
-
- mixin.setShown(true);
- assertNotNull("PeekProgressBar should be available after setting to shown",
- mixin.peekProgressBar());
- }
-
- @Test
- public void testSetColorBeforeSetShown() {
- ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
- mixin.setColor(ColorStateList.valueOf(Color.MAGENTA));
-
- mixin.setShown(true);
-
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- ProgressBar progressBar = (ProgressBar) mTemplateLayout.findViewById(
- R.id.suw_layout_progress);
- assertEquals(ColorStateList.valueOf(Color.MAGENTA),
- progressBar.getIndeterminateTintList());
- assertEquals(ColorStateList.valueOf(Color.MAGENTA),
- progressBar.getProgressBackgroundTintList());
- }
- // this method is a no-op on versions < lollipop. Just check that it doesn't crash.
- }
-
- @Test
- public void testSetColorAfterSetShown() {
- ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
- mixin.setShown(true);
-
- mixin.setColor(ColorStateList.valueOf(Color.YELLOW));
-
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- ProgressBar progressBar = (ProgressBar) mTemplateLayout.findViewById(
- R.id.suw_layout_progress);
- assertEquals(ColorStateList.valueOf(Color.YELLOW),
- progressBar.getIndeterminateTintList());
- assertEquals(ColorStateList.valueOf(Color.YELLOW),
- progressBar.getProgressBackgroundTintList());
- }
- // this method is a no-op on versions < lollipop. Just check that it doesn't crash.
- }
-
- @Test
- public void testDeterminateProgressBarNullTint() {
- ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
- mixin.setShown(true);
- mixin.peekProgressBar().setIndeterminate(false);
-
- mixin.setColor(null);
-
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- ProgressBar progressBar = (ProgressBar) mTemplateLayout.findViewById(
- R.id.suw_layout_progress);
- assertEquals(null, progressBar.getProgressBackgroundTintList());
- progressBar.draw(new Canvas());
- }
- // setColor is a no-op on versions < lollipop. Just check that it doesn't crash.
+ // this method is a no-op on versions < lollipop. Just check that it doesn't crash.
+ }
+
+ @Test
+ public void testDeterminateProgressBarNullTint() {
+ ProgressBarMixin mixin = new ProgressBarMixin(mTemplateLayout);
+ mixin.setShown(true);
+ mixin.peekProgressBar().setIndeterminate(false);
+
+ mixin.setColor(null);
+
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ ProgressBar progressBar =
+ (ProgressBar) mTemplateLayout.findViewById(R.id.suw_layout_progress);
+ assertEquals(null, progressBar.getProgressBackgroundTintList());
+ progressBar.draw(new Canvas());
}
+ // setColor is a no-op on versions < lollipop. Just check that it doesn't crash.
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/template/TemplateLayoutMixinTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/template/TemplateLayoutMixinTest.java
index 7cc934a..6adebc6 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/template/TemplateLayoutMixinTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/template/TemplateLayoutMixinTest.java
@@ -24,10 +24,8 @@ import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-
import com.android.setupwizardlib.TemplateLayout;
import com.android.setupwizardlib.test.R;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,35 +34,38 @@ import org.junit.runner.RunWith;
@SmallTest
public class TemplateLayoutMixinTest {
- private TestTemplateLayout mLayout;
+ private TestTemplateLayout mLayout;
- @Before
- public void setUp() throws Exception {
- mLayout = new TestTemplateLayout(InstrumentationRegistry.getContext());
- }
+ @Before
+ public void setUp() throws Exception {
+ mLayout = new TestTemplateLayout(InstrumentationRegistry.getContext());
+ }
- @Test
- public void testGetMixin() {
- final TestMixin mixin = mLayout.getMixin(TestMixin.class);
- assertNotNull("TestMixin should not be null", mixin);
- assertTrue("TestMixin should be an instance of TestMixinSubclass. "
- + "Found " + mixin.getClass() + " instead.",
- mixin instanceof TestMixinSubclass);
+ @Test
+ public void testGetMixin() {
+ final TestMixin mixin = mLayout.getMixin(TestMixin.class);
+ assertNotNull("TestMixin should not be null", mixin);
+ assertTrue(
+ "TestMixin should be an instance of TestMixinSubclass. "
+ + "Found "
+ + mixin.getClass()
+ + " instead.",
+ mixin instanceof TestMixinSubclass);
- // Mixin must be retrieved using the interface it's registered with, not the concrete class,
- // although they are often the same.
- assertNull("TestMixinSubclass should be null", mLayout.getMixin(TestMixinSubclass.class));
- }
+ // Mixin must be retrieved using the interface it's registered with, not the concrete class,
+ // although they are often the same.
+ assertNull("TestMixinSubclass should be null", mLayout.getMixin(TestMixinSubclass.class));
+ }
- private static class TestTemplateLayout extends TemplateLayout {
+ private static class TestTemplateLayout extends TemplateLayout {
- TestTemplateLayout(Context context) {
- super(context, R.layout.test_template, R.id.suw_layout_content);
- registerMixin(TestMixin.class, new TestMixinSubclass());
- }
+ TestTemplateLayout(Context context) {
+ super(context, R.layout.test_template, R.id.suw_layout_content);
+ registerMixin(TestMixin.class, new TestMixinSubclass());
}
+ }
- private static class TestMixin implements Mixin {}
+ private static class TestMixin implements Mixin {}
- private static class TestMixinSubclass extends TestMixin {}
+ private static class TestMixinSubclass extends TestMixin {}
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/BottomScrollViewTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/BottomScrollViewTest.java
index 1a8eb21..4f9487c 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/BottomScrollViewTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/BottomScrollViewTest.java
@@ -21,13 +21,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.content.Context;
+import android.view.View;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-
import com.android.setupwizardlib.view.BottomScrollView;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,101 +34,101 @@ import org.junit.runner.RunWith;
@SmallTest
public class BottomScrollViewTest {
- private TestBottomScrollListener mListener;
+ private TestBottomScrollListener mListener;
- @Before
- public void setUp() throws Exception {
- mListener = new TestBottomScrollListener();
- }
+ @Before
+ public void setUp() throws Exception {
+ mListener = new TestBottomScrollListener();
+ }
- @Test
- public void testNoNeedScroll() {
- createScrollView(20);
- assertTrue("Scroll should not be required", mListener.mScrolledToBottom);
- }
+ @Test
+ public void testNoNeedScroll() {
+ createScrollView(20);
+ assertTrue("Scroll should not be required", mListener.mScrolledToBottom);
+ }
- @Test
- public void testNeedScroll() {
- createScrollView(110);
- assertFalse("Scroll should be required", mListener.mScrolledToBottom);
- }
+ @Test
+ public void testNeedScroll() {
+ createScrollView(110);
+ assertFalse("Scroll should be required", mListener.mScrolledToBottom);
+ }
- @Test
- public void testScrollToBottom() {
- final BottomScrollView bottomScrollView = createScrollView(110);
+ @Test
+ public void testScrollToBottom() {
+ final BottomScrollView bottomScrollView = createScrollView(110);
- assertFalse("Scroll should be required", mListener.mScrolledToBottom);
+ assertFalse("Scroll should be required", mListener.mScrolledToBottom);
- bottomScrollView.scrollTo(0, 10);
- assertTrue("Should already be scrolled to bottom", mListener.mScrolledToBottom);
- }
+ bottomScrollView.scrollTo(0, 10);
+ assertTrue("Should already be scrolled to bottom", mListener.mScrolledToBottom);
+ }
- @Test
- public void testScrollThreshold() {
- final BottomScrollView bottomScrollView = createScrollView(110);
- assertEquals("Scroll threshold should be 10", 10, bottomScrollView.getScrollThreshold());
- }
+ @Test
+ public void testScrollThreshold() {
+ final BottomScrollView bottomScrollView = createScrollView(110);
+ assertEquals("Scroll threshold should be 10", 10, bottomScrollView.getScrollThreshold());
+ }
- private BottomScrollView createScrollView(final int childHeight) {
- final Context context = InstrumentationRegistry.getContext();
- final BottomScrollView bottomScrollView = new TestBottomScrollView(context);
- bottomScrollView.setBottomScrollListener(mListener);
+ private BottomScrollView createScrollView(final int childHeight) {
+ final Context context = InstrumentationRegistry.getContext();
+ final BottomScrollView bottomScrollView = new TestBottomScrollView(context);
+ bottomScrollView.setBottomScrollListener(mListener);
- final View child = new TestChildView(context, childHeight);
+ final View child = new TestChildView(context, childHeight);
- child.measure(0, 0); // TestChildView's measured dimensions doesn't depend on the arguments
- bottomScrollView.addView(child);
- bottomScrollView.layout(0, 0, 100, 100);
+ child.measure(0, 0); // TestChildView's measured dimensions doesn't depend on the arguments
+ bottomScrollView.addView(child);
+ bottomScrollView.layout(0, 0, 100, 100);
- return bottomScrollView;
- }
+ return bottomScrollView;
+ }
- private static class TestChildView extends View {
+ private static class TestChildView extends View {
- private static final int WIDTH = 10;
- private int mHeight;
+ private static final int WIDTH = 10;
+ private int mHeight;
- TestChildView(Context context, int height) {
- super(context);
- mHeight = height;
- }
+ TestChildView(Context context, int height) {
+ super(context);
+ mHeight = height;
+ }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(WIDTH, mHeight);
- }
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(WIDTH, mHeight);
+ }
- public void setHeight(int height) {
- mHeight = height;
- }
+ public void setHeight(int height) {
+ mHeight = height;
}
+ }
- private static class TestBottomScrollView extends BottomScrollView {
+ private static class TestBottomScrollView extends BottomScrollView {
- TestBottomScrollView(Context context) {
- super(context);
- }
+ TestBottomScrollView(Context context) {
+ super(context);
+ }
- @Override
- public boolean post(Runnable action) {
- // Post all runnables synchronously so that tests can check the callbacks.
- action.run();
- return true;
- }
+ @Override
+ public boolean post(Runnable action) {
+ // Post all runnables synchronously so that tests can check the callbacks.
+ action.run();
+ return true;
}
+ }
- private static class TestBottomScrollListener implements BottomScrollView.BottomScrollListener {
+ private static class TestBottomScrollListener implements BottomScrollView.BottomScrollListener {
- boolean mScrolledToBottom = true;
+ boolean mScrolledToBottom = true;
- @Override
- public void onScrolledToBottom() {
- mScrolledToBottom = true;
- }
+ @Override
+ public void onScrolledToBottom() {
+ mScrolledToBottom = true;
+ }
- @Override
- public void onRequiresScroll() {
- mScrolledToBottom = false;
- }
+ @Override
+ public void onRequiresScroll() {
+ mScrolledToBottom = false;
}
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/ButtonBarItemTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/ButtonBarItemTest.java
index 18c295e..aacffeb 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/ButtonBarItemTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/ButtonBarItemTest.java
@@ -20,18 +20,16 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.items.ButtonBarItem;
import com.android.setupwizardlib.items.ButtonItem;
import com.android.setupwizardlib.items.Item;
import com.android.setupwizardlib.items.ItemHierarchy;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,87 +38,92 @@ import org.junit.runner.RunWith;
@SmallTest
public class ButtonBarItemTest {
- private ButtonItem mChild1;
- private ButtonItem mChild2;
- private ButtonItem mChild3;
-
- @Before
- public void setUp() throws Exception {
- mChild1 = new ButtonItem();
- mChild2 = new ButtonItem();
- mChild3 = new ButtonItem();
+ private ButtonItem mChild1;
+ private ButtonItem mChild2;
+ private ButtonItem mChild3;
+
+ @Before
+ public void setUp() throws Exception {
+ mChild1 = new ButtonItem();
+ mChild2 = new ButtonItem();
+ mChild3 = new ButtonItem();
+ }
+
+ @Test
+ public void testFindItemById() {
+ ButtonBarItem item = new ButtonBarItem();
+ item.setId(888);
+
+ mChild1.setId(123);
+ mChild2.setId(456);
+ mChild3.setId(789);
+ item.addChild(mChild1);
+ item.addChild(mChild2);
+ item.addChild(mChild3);
+
+ assertEquals("Finding 123 should return child1", mChild1, item.findItemById(123));
+ assertEquals("Finding 456 should return child2", mChild2, item.findItemById(456));
+ assertEquals("Finding 789 should return child3", mChild3, item.findItemById(789));
+
+ assertEquals("Finding 888 should return ButtonBarItem itself", item, item.findItemById(888));
+
+ assertNull("Finding 999 should return null", item.findItemById(999));
+ }
+
+ @Test
+ public void testBindEmpty() {
+ ButtonBarItem item = new ButtonBarItem();
+ final ViewGroup layout = createLayout();
+ item.onBindView(layout);
+
+ assertEquals(
+ "Binding empty ButtonBar should not create any children", 0, layout.getChildCount());
+ }
+
+ @Test
+ public void testBind() {
+ ButtonBarItem item = new ButtonBarItem();
+
+ item.addChild(mChild1);
+ mChild1.setText("child1");
+ item.addChild(mChild2);
+ mChild2.setText("child2");
+ item.addChild(mChild3);
+ mChild3.setText("child3");
+
+ final ViewGroup layout = createLayout();
+ item.onBindView(layout);
+
+ assertEquals("Binding ButtonBar should create 3 children", 3, layout.getChildCount());
+ assertEquals(
+ "First button should have text \"child1\"",
+ "child1",
+ ((Button) layout.getChildAt(0)).getText());
+ assertEquals(
+ "Second button should have text \"child2\"",
+ "child2",
+ ((Button) layout.getChildAt(1)).getText());
+ assertEquals(
+ "Third button should have text \"child3\"",
+ "child3",
+ ((Button) layout.getChildAt(2)).getText());
+ }
+
+ @Test
+ public void testAddInvalidChild() {
+ ButtonBarItem item = new ButtonBarItem();
+
+ ItemHierarchy invalidChild = new Item();
+
+ try {
+ item.addChild(invalidChild);
+ fail("Adding non ButtonItem to ButtonBarItem should throw exception");
+ } catch (UnsupportedOperationException e) {
+ // pass
}
+ }
- @Test
- public void testFindItemById() {
- ButtonBarItem item = new ButtonBarItem();
- item.setId(888);
-
- mChild1.setId(123);
- mChild2.setId(456);
- mChild3.setId(789);
- item.addChild(mChild1);
- item.addChild(mChild2);
- item.addChild(mChild3);
-
- assertEquals("Finding 123 should return child1", mChild1, item.findItemById(123));
- assertEquals("Finding 456 should return child2", mChild2, item.findItemById(456));
- assertEquals("Finding 789 should return child3", mChild3, item.findItemById(789));
-
- assertEquals("Finding 888 should return ButtonBarItem itself", item,
- item.findItemById(888));
-
- assertNull("Finding 999 should return null", item.findItemById(999));
- }
-
- @Test
- public void testBindEmpty() {
- ButtonBarItem item = new ButtonBarItem();
- final ViewGroup layout = createLayout();
- item.onBindView(layout);
-
- assertEquals("Binding empty ButtonBar should not create any children", 0,
- layout.getChildCount());
- }
-
- @Test
- public void testBind() {
- ButtonBarItem item = new ButtonBarItem();
-
- item.addChild(mChild1);
- mChild1.setText("child1");
- item.addChild(mChild2);
- mChild2.setText("child2");
- item.addChild(mChild3);
- mChild3.setText("child3");
-
- final ViewGroup layout = createLayout();
- item.onBindView(layout);
-
- assertEquals("Binding ButtonBar should create 3 children", 3, layout.getChildCount());
- assertEquals("First button should have text \"child1\"", "child1",
- ((Button) layout.getChildAt(0)).getText());
- assertEquals("Second button should have text \"child2\"", "child2",
- ((Button) layout.getChildAt(1)).getText());
- assertEquals("Third button should have text \"child3\"", "child3",
- ((Button) layout.getChildAt(2)).getText());
- }
-
- @Test
- public void testAddInvalidChild() {
- ButtonBarItem item = new ButtonBarItem();
-
- ItemHierarchy invalidChild = new Item();
-
- try {
- item.addChild(invalidChild);
- fail("Adding non ButtonItem to ButtonBarItem should throw exception");
- } catch (UnsupportedOperationException e) {
- // pass
- }
- }
-
- private ViewGroup createLayout() {
- return new LinearLayout(InstrumentationRegistry.getContext());
- }
+ private ViewGroup createLayout() {
+ return new LinearLayout(InstrumentationRegistry.getContext());
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/DrawableLayoutDirectionHelperTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/DrawableLayoutDirectionHelperTest.java
index 95245b0..1445660 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/DrawableLayoutDirectionHelperTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/DrawableLayoutDirectionHelperTest.java
@@ -28,117 +28,124 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
+import android.view.View;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-
import com.android.setupwizardlib.util.DrawableLayoutDirectionHelper;
-
+import java.util.Locale;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.Locale;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DrawableLayoutDirectionHelperTest {
- @Test
- public void testCreateRelativeInsetDrawableLtr() {
- final Drawable drawable = new ColorDrawable(Color.RED);
- @SuppressLint("InlinedApi") // Testing with inlined constant is OK here
- final InsetDrawable insetDrawable =
- DrawableLayoutDirectionHelper.createRelativeInsetDrawable(drawable,
- 1 /* start */, 2 /* top */, 3 /* end */, 4 /* bottom */,
- View.LAYOUT_DIRECTION_LTR);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- assertSame("Drawable from getDrawable() should be same as passed in", drawable,
- insetDrawable.getDrawable());
- }
- Rect outRect = new Rect();
- insetDrawable.getPadding(outRect);
- assertEquals("InsetDrawable padding should be same as inset", new Rect(1, 2, 3, 4),
- outRect);
+ @Test
+ public void testCreateRelativeInsetDrawableLtr() {
+ final Drawable drawable = new ColorDrawable(Color.RED);
+ @SuppressLint("InlinedApi") // Testing with inlined constant is OK here
+ final InsetDrawable insetDrawable =
+ DrawableLayoutDirectionHelper.createRelativeInsetDrawable(
+ drawable,
+ 1 /* start */,
+ 2 /* top */,
+ 3 /* end */,
+ 4 /* bottom */,
+ View.LAYOUT_DIRECTION_LTR);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ assertSame(
+ "Drawable from getDrawable() should be same as passed in",
+ drawable,
+ insetDrawable.getDrawable());
}
+ Rect outRect = new Rect();
+ insetDrawable.getPadding(outRect);
+ assertEquals("InsetDrawable padding should be same as inset", new Rect(1, 2, 3, 4), outRect);
+ }
- @Test
- public void testCreateRelativeInsetDrawableRtl() {
- final Drawable drawable = new ColorDrawable(Color.RED);
- @SuppressLint("InlinedApi") // Testing with inlined constant is OK here
- final InsetDrawable insetDrawable =
- DrawableLayoutDirectionHelper.createRelativeInsetDrawable(drawable,
- 1 /* start */, 2 /* top */, 3 /* end */, 4 /* bottom */,
- View.LAYOUT_DIRECTION_RTL);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- assertSame("Drawable from getDrawable() should be same as passed in", drawable,
- insetDrawable.getDrawable());
- }
- Rect outRect = new Rect();
- insetDrawable.getPadding(outRect);
- assertEquals("InsetDrawable padding should be same as inset", new Rect(3, 2, 1, 4),
- outRect);
+ @Test
+ public void testCreateRelativeInsetDrawableRtl() {
+ final Drawable drawable = new ColorDrawable(Color.RED);
+ @SuppressLint("InlinedApi") // Testing with inlined constant is OK here
+ final InsetDrawable insetDrawable =
+ DrawableLayoutDirectionHelper.createRelativeInsetDrawable(
+ drawable,
+ 1 /* start */,
+ 2 /* top */,
+ 3 /* end */,
+ 4 /* bottom */,
+ View.LAYOUT_DIRECTION_RTL);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ assertSame(
+ "Drawable from getDrawable() should be same as passed in",
+ drawable,
+ insetDrawable.getDrawable());
}
+ Rect outRect = new Rect();
+ insetDrawable.getPadding(outRect);
+ assertEquals("InsetDrawable padding should be same as inset", new Rect(3, 2, 1, 4), outRect);
+ }
- @Test
- public void testCreateRelativeInsetDrawableViewRtl() {
- final Drawable drawable = new ColorDrawable(Color.RED);
- final View view = new ForceRtlView(InstrumentationRegistry.getContext());
- final InsetDrawable insetDrawable =
- DrawableLayoutDirectionHelper.createRelativeInsetDrawable(drawable,
- 1 /* start */, 2 /* top */, 3 /* end */, 4 /* bottom */, view);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- assertSame("Drawable from getDrawable() should be same as passed in", drawable,
- insetDrawable.getDrawable());
- }
- Rect outRect = new Rect();
- insetDrawable.getPadding(outRect);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- assertEquals("InsetDrawable padding should be same as inset", new Rect(3, 2, 1, 4),
- outRect);
- } else {
- assertEquals("InsetDrawable padding should be same as inset", new Rect(1, 2, 3, 4),
- outRect);
- }
+ @Test
+ public void testCreateRelativeInsetDrawableViewRtl() {
+ final Drawable drawable = new ColorDrawable(Color.RED);
+ final View view = new ForceRtlView(InstrumentationRegistry.getContext());
+ final InsetDrawable insetDrawable =
+ DrawableLayoutDirectionHelper.createRelativeInsetDrawable(
+ drawable, 1 /* start */, 2 /* top */, 3 /* end */, 4 /* bottom */, view);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ assertSame(
+ "Drawable from getDrawable() should be same as passed in",
+ drawable,
+ insetDrawable.getDrawable());
+ }
+ Rect outRect = new Rect();
+ insetDrawable.getPadding(outRect);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ assertEquals("InsetDrawable padding should be same as inset", new Rect(3, 2, 1, 4), outRect);
+ } else {
+ assertEquals("InsetDrawable padding should be same as inset", new Rect(1, 2, 3, 4), outRect);
}
+ }
- @Test
- public void testCreateRelativeInsetDrawableContextRtl() {
- Context context = InstrumentationRegistry.getContext();
- final Drawable drawable = new ColorDrawable(Color.RED);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- final Configuration config = new Configuration();
- config.setLayoutDirection(new Locale("fa", "IR"));
- context = context.createConfigurationContext(config);
- }
- final InsetDrawable insetDrawable =
- DrawableLayoutDirectionHelper.createRelativeInsetDrawable(drawable,
- 1 /* start */, 2 /* top */, 3 /* end */, 4 /* bottom */, context);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- assertSame("Drawable from getDrawable() should be same as passed in", drawable,
- insetDrawable.getDrawable());
- }
- Rect outRect = new Rect();
- insetDrawable.getPadding(outRect);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- assertEquals("InsetDrawable padding should be same as inset", new Rect(3, 2, 1, 4),
- outRect);
- } else {
- assertEquals("InsetDrawable padding should be same as inset", new Rect(1, 2, 3, 4),
- outRect);
- }
+ @Test
+ public void testCreateRelativeInsetDrawableContextRtl() {
+ Context context = InstrumentationRegistry.getContext();
+ final Drawable drawable = new ColorDrawable(Color.RED);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ final Configuration config = new Configuration();
+ config.setLayoutDirection(new Locale("fa", "IR"));
+ context = context.createConfigurationContext(config);
+ }
+ final InsetDrawable insetDrawable =
+ DrawableLayoutDirectionHelper.createRelativeInsetDrawable(
+ drawable, 1 /* start */, 2 /* top */, 3 /* end */, 4 /* bottom */, context);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ assertSame(
+ "Drawable from getDrawable() should be same as passed in",
+ drawable,
+ insetDrawable.getDrawable());
}
+ Rect outRect = new Rect();
+ insetDrawable.getPadding(outRect);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ assertEquals("InsetDrawable padding should be same as inset", new Rect(3, 2, 1, 4), outRect);
+ } else {
+ assertEquals("InsetDrawable padding should be same as inset", new Rect(1, 2, 3, 4), outRect);
+ }
+ }
- private static class ForceRtlView extends View {
+ private static class ForceRtlView extends View {
- ForceRtlView(Context context) {
- super(context);
- }
+ ForceRtlView(Context context) {
+ super(context);
+ }
- @Override
- @SuppressLint("InlinedApi") // Testing with inlined constant is OK here
- public int getLayoutDirection() {
- return View.LAYOUT_DIRECTION_RTL;
- }
+ @Override
+ @SuppressLint("InlinedApi") // Testing with inlined constant is OK here
+ public int getLayoutDirection() {
+ return View.LAYOUT_DIRECTION_RTL;
}
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifLayoutTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifLayoutTest.java
index e12b31d..f8aae5a 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifLayoutTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifLayoutTest.java
@@ -26,9 +26,6 @@ import android.content.res.ColorStateList;
import android.graphics.Color;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -36,9 +33,10 @@ import android.view.View;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.GlifLayout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,94 +45,99 @@ import org.junit.runner.RunWith;
@SmallTest
public class GlifLayoutTest {
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeGlif_Light);
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext =
+ new ContextThemeWrapper(InstrumentationRegistry.getContext(), R.style.SuwThemeGlif_Light);
+ }
+
+ @Test
+ public void testInflateFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ GlifLayout layout = (GlifLayout) inflater.inflate(R.layout.test_glif_layout, null);
+ assertDefaultTemplateInflated(layout);
+ View content = layout.findViewById(R.id.test_content);
+ assertTrue("@id/test_content should be a TextView", content instanceof TextView);
+ }
+
+ @Test
+ public void testPrimaryColorFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ GlifLayout layout =
+ (GlifLayout) inflater.inflate(R.layout.test_glif_layout_primary_color, null);
+ assertDefaultTemplateInflated(layout);
+
+ assertEquals(ColorStateList.valueOf(Color.RED), layout.getPrimaryColor());
+ }
+
+ @Test
+ public void testSetProgressBarShownInvalid() {
+ GlifLayout layout = new GlifLayout(mContext, R.layout.test_template);
+ layout.setProgressBarShown(true);
+ // This is a no-op because there is no progress bar stub
+ }
+
+ @Test
+ public void testGlifTheme() {
+ mContext =
+ new ContextThemeWrapper(InstrumentationRegistry.getContext(), R.style.SuwThemeGlif_Light);
+ final GlifLayout glifLayout = new GlifLayout(mContext);
+
+ if (VERSION.SDK_INT >= VERSION_CODES.M) {
+ // Scroll indicators are only available on versions >= M
+ assertEquals(View.SCROLL_INDICATOR_BOTTOM, glifLayout.getScrollView().getScrollIndicators());
}
-
- @Test
- public void testInflateFromXml() {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- GlifLayout layout = (GlifLayout) inflater.inflate(R.layout.test_glif_layout, null);
- assertDefaultTemplateInflated(layout);
- View content = layout.findViewById(R.id.test_content);
- assertTrue("@id/test_content should be a TextView", content instanceof TextView);
- }
-
- @Test
- public void testPrimaryColorFromXml() {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- GlifLayout layout =
- (GlifLayout) inflater.inflate(R.layout.test_glif_layout_primary_color, null);
- assertDefaultTemplateInflated(layout);
-
- assertEquals(ColorStateList.valueOf(Color.RED), layout.getPrimaryColor());
+ }
+
+ @Test
+ public void testGlifV2Theme() {
+ mContext =
+ new ContextThemeWrapper(InstrumentationRegistry.getContext(), R.style.SuwThemeGlifV2_Light);
+ final GlifLayout glifLayout = new GlifLayout(mContext);
+ final TextView titleView = (TextView) glifLayout.findManagedViewById(R.id.suw_layout_title);
+ if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
+ assertEquals(View.TEXT_ALIGNMENT_GRAVITY, titleView.getTextAlignment());
}
-
- @Test
- public void testSetProgressBarShownInvalid() {
- GlifLayout layout = new GlifLayout(mContext, R.layout.test_template);
- layout.setProgressBarShown(true);
- // This is a no-op because there is no progress bar stub
- }
-
- @Test
- public void testGlifTheme() {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeGlif_Light);
- final GlifLayout glifLayout = new GlifLayout(mContext);
-
- if (VERSION.SDK_INT >= VERSION_CODES.M) {
- // Scroll indicators are only available on versions >= M
- assertEquals(View.SCROLL_INDICATOR_BOTTOM,
- glifLayout.getScrollView().getScrollIndicators());
- }
+ assertEquals(
+ "Title text should be center aligned on GLIF v2 theme",
+ Gravity.CENTER_HORIZONTAL,
+ titleView.getGravity() & Gravity.CENTER_HORIZONTAL);
+
+ if (VERSION.SDK_INT >= VERSION_CODES.N) {
+ // LinearLayout.getGravity is only available on versions >= N
+ final View iconView = glifLayout.findManagedViewById(R.id.suw_layout_icon);
+ final LinearLayout parent = (LinearLayout) iconView.getParent();
+ assertEquals(
+ "Icon should be center aligned on GLIF v2 theme",
+ Gravity.CENTER_HORIZONTAL,
+ parent.getGravity() & Gravity.CENTER_HORIZONTAL);
}
- @Test
- public void testGlifV2Theme() {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeGlifV2_Light);
- final GlifLayout glifLayout = new GlifLayout(mContext);
- final TextView titleView = (TextView) glifLayout.findManagedViewById(R.id.suw_layout_title);
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
- assertEquals(View.TEXT_ALIGNMENT_GRAVITY, titleView.getTextAlignment());
- }
- assertEquals("Title text should be center aligned on GLIF v2 theme",
- Gravity.CENTER_HORIZONTAL, titleView.getGravity() & Gravity.CENTER_HORIZONTAL);
-
- if (VERSION.SDK_INT >= VERSION_CODES.N) {
- // LinearLayout.getGravity is only available on versions >= N
- final View iconView = glifLayout.findManagedViewById(R.id.suw_layout_icon);
- final LinearLayout parent = (LinearLayout) iconView.getParent();
- assertEquals("Icon should be center aligned on GLIF v2 theme",
- Gravity.CENTER_HORIZONTAL, parent.getGravity() & Gravity.CENTER_HORIZONTAL);
- }
-
- assertEquals("Status bar color should be white in GLIF v2 theme",
- "ffffffff",
- Integer.toHexString(glifLayout.getBackgroundBaseColor().getDefaultColor()));
- assertFalse("GLIF v2 theme shuold not have patterned background",
- glifLayout.isBackgroundPatterned());
-
- if (VERSION.SDK_INT >= VERSION_CODES.M) {
- // Scroll indicators are only available on versions >= M
- assertEquals(View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM,
- glifLayout.getScrollView().getScrollIndicators());
- }
+ assertEquals(
+ "Status bar color should be white in GLIF v2 theme",
+ "ffffffff",
+ Integer.toHexString(glifLayout.getBackgroundBaseColor().getDefaultColor()));
+ assertFalse(
+ "GLIF v2 theme shuold not have patterned background", glifLayout.isBackgroundPatterned());
+
+ if (VERSION.SDK_INT >= VERSION_CODES.M) {
+ // Scroll indicators are only available on versions >= M
+ assertEquals(
+ View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM,
+ glifLayout.getScrollView().getScrollIndicators());
}
+ }
- private void assertDefaultTemplateInflated(GlifLayout layout) {
- View title = layout.findViewById(R.id.suw_layout_title);
- assertNotNull("@id/suw_layout_title should not be null", title);
+ private void assertDefaultTemplateInflated(GlifLayout layout) {
+ View title = layout.findViewById(R.id.suw_layout_title);
+ assertNotNull("@id/suw_layout_title should not be null", title);
- View icon = layout.findViewById(R.id.suw_layout_icon);
- assertNotNull("@id/suw_layout_icon should not be null", icon);
+ View icon = layout.findViewById(R.id.suw_layout_icon);
+ assertNotNull("@id/suw_layout_icon should not be null", icon);
- View scrollView = layout.findViewById(R.id.suw_scroll_view);
- assertTrue("@id/suw_scroll_view should be a ScrollView", scrollView instanceof ScrollView);
- }
+ View scrollView = layout.findViewById(R.id.suw_scroll_view);
+ assertTrue("@id/suw_scroll_view should be a ScrollView", scrollView instanceof ScrollView);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifListLayoutTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifListLayoutTest.java
index c2e932c..0665bfe 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifListLayoutTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifListLayoutTest.java
@@ -26,9 +26,6 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,9 +33,10 @@ import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.GlifListLayout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,102 +45,100 @@ import org.junit.runner.RunWith;
@SmallTest
public class GlifListLayoutTest {
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeGlif_Light);
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext =
+ new ContextThemeWrapper(InstrumentationRegistry.getContext(), R.style.SuwThemeGlif_Light);
+ }
+
+ @Test
+ public void testDefaultTemplate() {
+ GlifListLayout layout = new GlifListLayout(mContext);
+ assertListTemplateInflated(layout);
+ }
+
+ @Test
+ public void testAddView() {
+ GlifListLayout layout = new GlifListLayout(mContext);
+ TextView tv = new TextView(mContext);
+ try {
+ layout.addView(tv);
+ fail("Adding view to ListLayout should throw");
+ } catch (UnsupportedOperationException e) {
+ // Expected exception
}
-
- @Test
- public void testDefaultTemplate() {
- GlifListLayout layout = new GlifListLayout(mContext);
- assertListTemplateInflated(layout);
+ }
+
+ @Test
+ public void testInflateFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ GlifListLayout layout = (GlifListLayout) inflater.inflate(R.layout.test_glif_list_layout, null);
+ assertListTemplateInflated(layout);
+ }
+
+ @Test
+ public void testGetListView() {
+ GlifListLayout layout = new GlifListLayout(mContext);
+ assertListTemplateInflated(layout);
+ assertNotNull("getListView should not be null", layout.getListView());
+ }
+
+ @Test
+ public void testAdapter() {
+ GlifListLayout layout = new GlifListLayout(mContext);
+ assertListTemplateInflated(layout);
+
+ final ArrayAdapter<String> adapter =
+ new ArrayAdapter<>(mContext, android.R.layout.simple_list_item_1);
+ adapter.add("Abracadabra");
+ layout.setAdapter(adapter);
+
+ final ListAdapter gotAdapter = layout.getAdapter();
+ // Note: the wrapped adapter should be returned directly, not the HeaderViewListAdapter.
+ assertSame("Adapter got from GlifListLayout should be same as set", adapter, gotAdapter);
+ }
+
+ @Test
+ public void testDividerInsetLegacy() {
+ GlifListLayout layout = new GlifListLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
+ assertListTemplateInflated(layout);
- @Test
- public void testAddView() {
- GlifListLayout layout = new GlifListLayout(mContext);
- TextView tv = new TextView(mContext);
- try {
- layout.addView(tv);
- fail("Adding view to ListLayout should throw");
- } catch (UnsupportedOperationException e) {
- // Expected exception
- }
- }
+ layout.setDividerInset(10);
+ assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
- @Test
- public void testInflateFromXml() {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- GlifListLayout layout = (GlifListLayout)
- inflater.inflate(R.layout.test_glif_list_layout, null);
- assertListTemplateInflated(layout);
- }
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
- @Test
- public void testGetListView() {
- GlifListLayout layout = new GlifListLayout(mContext);
- assertListTemplateInflated(layout);
- assertNotNull("getListView should not be null", layout.getListView());
+ @Test
+ public void testDividerInsets() {
+ GlifListLayout layout = new GlifListLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
+ assertListTemplateInflated(layout);
- @Test
- public void testAdapter() {
- GlifListLayout layout = new GlifListLayout(mContext);
- assertListTemplateInflated(layout);
+ layout.setDividerInsets(10, 15);
+ assertEquals("Divider inset should be 10", 10, layout.getDividerInsetStart());
+ assertEquals("Divider inset should be 15", 15, layout.getDividerInsetEnd());
- final ArrayAdapter<String> adapter =
- new ArrayAdapter<>(mContext, android.R.layout.simple_list_item_1);
- adapter.add("Abracadabra");
- layout.setAdapter(adapter);
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
- final ListAdapter gotAdapter = layout.getAdapter();
- // Note: the wrapped adapter should be returned directly, not the HeaderViewListAdapter.
- assertSame("Adapter got from GlifListLayout should be same as set",
- adapter, gotAdapter);
- }
-
- @Test
- public void testDividerInsetLegacy() {
- GlifListLayout layout = new GlifListLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertListTemplateInflated(layout);
-
- layout.setDividerInset(10);
- assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
-
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
-
- @Test
- public void testDividerInsets() {
- GlifListLayout layout = new GlifListLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertListTemplateInflated(layout);
+ private void assertListTemplateInflated(GlifListLayout layout) {
+ View title = layout.findViewById(R.id.suw_layout_title);
+ assertNotNull("@id/suw_layout_title should not be null", title);
- layout.setDividerInsets(10, 15);
- assertEquals("Divider inset should be 10", 10, layout.getDividerInsetStart());
- assertEquals("Divider inset should be 15", 15, layout.getDividerInsetEnd());
+ View icon = layout.findViewById(R.id.suw_layout_icon);
+ assertNotNull("@id/suw_layout_icon should not be null", icon);
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
-
- private void assertListTemplateInflated(GlifListLayout layout) {
- View title = layout.findViewById(R.id.suw_layout_title);
- assertNotNull("@id/suw_layout_title should not be null", title);
-
- View icon = layout.findViewById(R.id.suw_layout_icon);
- assertNotNull("@id/suw_layout_icon should not be null", icon);
-
- View listView = layout.findViewById(android.R.id.list);
- assertTrue("@android:id/list should be a ListView", listView instanceof ListView);
- }
+ View listView = layout.findViewById(android.R.id.list);
+ assertTrue("@android:id/list should be a ListView", listView instanceof ListView);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifPatternDrawableTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifPatternDrawableTest.java
index 37ac41a..1783d4e 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifPatternDrawableTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/GlifPatternDrawableTest.java
@@ -25,14 +25,11 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Debug;
+import android.util.Log;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
-
import com.android.setupwizardlib.GlifPatternDrawable;
-
import junit.framework.AssertionFailedError;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,141 +38,144 @@ import org.junit.runner.RunWith;
@SmallTest
public class GlifPatternDrawableTest {
- private static final String TAG = "GlifPatternDrawableTest";
+ private static final String TAG = "GlifPatternDrawableTest";
- @Before
- public void setUp() throws Exception {
- GlifPatternDrawable.invalidatePattern();
- }
+ @Before
+ public void setUp() throws Exception {
+ GlifPatternDrawable.invalidatePattern();
+ }
- @Test
- public void testDraw() {
- final Bitmap bitmap = Bitmap.createBitmap(1366, 768, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(bitmap);
+ @Test
+ public void testDraw() {
+ final Bitmap bitmap = Bitmap.createBitmap(1366, 768, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
- final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
- drawable.setBounds(0, 0, 1366, 768);
- drawable.draw(canvas);
+ final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
+ drawable.setBounds(0, 0, 1366, 768);
+ drawable.draw(canvas);
- assertSameColor("Top left pixel should be #e61a1a", 0xffe61a1a, bitmap.getPixel(0, 0));
- assertSameColor("Center pixel should be #d90d0d", 0xffd90d0d, bitmap.getPixel(683, 384));
- assertSameColor("Bottom right pixel should be #d40808", 0xffd40808,
- bitmap.getPixel(1365, 767));
- }
+ assertSameColor("Top left pixel should be #e61a1a", 0xffe61a1a, bitmap.getPixel(0, 0));
+ assertSameColor("Center pixel should be #d90d0d", 0xffd90d0d, bitmap.getPixel(683, 384));
+ assertSameColor("Bottom right pixel should be #d40808", 0xffd40808, bitmap.getPixel(1365, 767));
+ }
- @Test
- public void testDrawTwice() {
- // Test that the second time the drawable is drawn is also correct, to make sure caching is
- // done correctly.
+ @Test
+ public void testDrawTwice() {
+ // Test that the second time the drawable is drawn is also correct, to make sure caching is
+ // done correctly.
- final Bitmap bitmap = Bitmap.createBitmap(1366, 768, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(bitmap);
+ final Bitmap bitmap = Bitmap.createBitmap(1366, 768, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
- final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
- drawable.setBounds(0, 0, 1366, 768);
- drawable.draw(canvas);
+ final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
+ drawable.setBounds(0, 0, 1366, 768);
+ drawable.draw(canvas);
- Paint paint = new Paint();
- paint.setColor(Color.WHITE);
- canvas.drawRect(0, 0, 1366, 768, paint); // Erase the entire canvas
+ Paint paint = new Paint();
+ paint.setColor(Color.WHITE);
+ canvas.drawRect(0, 0, 1366, 768, paint); // Erase the entire canvas
- drawable.draw(canvas);
+ drawable.draw(canvas);
- assertSameColor("Top left pixel should be #e61a1a", 0xffe61a1a, bitmap.getPixel(0, 0));
- assertSameColor("Center pixel should be #d90d0d", 0xffd90d0d, bitmap.getPixel(683, 384));
- assertSameColor("Bottom right pixel should be #d40808", 0xffd40808,
- bitmap.getPixel(1365, 767));
- }
+ assertSameColor("Top left pixel should be #e61a1a", 0xffe61a1a, bitmap.getPixel(0, 0));
+ assertSameColor("Center pixel should be #d90d0d", 0xffd90d0d, bitmap.getPixel(683, 384));
+ assertSameColor("Bottom right pixel should be #d40808", 0xffd40808, bitmap.getPixel(1365, 767));
+ }
- @Test
- public void testScaleToCanvasSquare() {
- final Canvas canvas = new Canvas();
- Matrix expected = new Matrix(canvas.getMatrix());
+ @Test
+ public void testScaleToCanvasSquare() {
+ final Canvas canvas = new Canvas();
+ Matrix expected = new Matrix(canvas.getMatrix());
- Bitmap mockBitmapCache = Bitmap.createBitmap(1366, 768, Bitmap.Config.ALPHA_8);
+ Bitmap mockBitmapCache = Bitmap.createBitmap(1366, 768, Bitmap.Config.ALPHA_8);
- final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
- drawable.setBounds(0, 0, 683, 384); // half each side of the view box
- drawable.scaleCanvasToBounds(canvas, mockBitmapCache, drawable.getBounds());
+ final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
+ drawable.setBounds(0, 0, 683, 384); // half each side of the view box
+ drawable.scaleCanvasToBounds(canvas, mockBitmapCache, drawable.getBounds());
- expected.postScale(0.5f, 0.5f);
+ expected.postScale(0.5f, 0.5f);
- assertEquals("Matrices should match", expected, canvas.getMatrix());
- }
+ assertEquals("Matrices should match", expected, canvas.getMatrix());
+ }
- @Test
- public void testScaleToCanvasTall() {
- final Canvas canvas = new Canvas();
- final Matrix expected = new Matrix(canvas.getMatrix());
+ @Test
+ public void testScaleToCanvasTall() {
+ final Canvas canvas = new Canvas();
+ final Matrix expected = new Matrix(canvas.getMatrix());
- Bitmap mockBitmapCache = Bitmap.createBitmap(1366, 768, Bitmap.Config.ALPHA_8);
+ Bitmap mockBitmapCache = Bitmap.createBitmap(1366, 768, Bitmap.Config.ALPHA_8);
- final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
- drawable.setBounds(0, 0, 683, 768); // half the width only
- drawable.scaleCanvasToBounds(canvas, mockBitmapCache, drawable.getBounds());
+ final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
+ drawable.setBounds(0, 0, 683, 768); // half the width only
+ drawable.scaleCanvasToBounds(canvas, mockBitmapCache, drawable.getBounds());
- expected.postScale(1f, 1f);
- expected.postTranslate(-99.718f, 0f);
+ expected.postScale(1f, 1f);
+ expected.postTranslate(-99.718f, 0f);
- assertEquals("Matrices should match", expected, canvas.getMatrix());
- }
+ assertEquals("Matrices should match", expected, canvas.getMatrix());
+ }
- @Test
- public void testScaleToCanvasWide() {
- final Canvas canvas = new Canvas();
- final Matrix expected = new Matrix(canvas.getMatrix());
+ @Test
+ public void testScaleToCanvasWide() {
+ final Canvas canvas = new Canvas();
+ final Matrix expected = new Matrix(canvas.getMatrix());
- Bitmap mockBitmapCache = Bitmap.createBitmap(1366, 768, Bitmap.Config.ALPHA_8);
+ Bitmap mockBitmapCache = Bitmap.createBitmap(1366, 768, Bitmap.Config.ALPHA_8);
- final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
- drawable.setBounds(0, 0, 1366, 384); // half the height only
- drawable.scaleCanvasToBounds(canvas, mockBitmapCache, drawable.getBounds());
+ final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
+ drawable.setBounds(0, 0, 1366, 384); // half the height only
+ drawable.scaleCanvasToBounds(canvas, mockBitmapCache, drawable.getBounds());
- expected.postScale(1f, 1f);
- expected.postTranslate(0f, -87.552f);
+ expected.postScale(1f, 1f);
+ expected.postTranslate(0f, -87.552f);
- assertEquals("Matrices should match", expected, canvas.getMatrix());
- }
+ assertEquals("Matrices should match", expected, canvas.getMatrix());
+ }
- @Test
- public void testScaleToCanvasMaxSize() {
- final Canvas canvas = new Canvas();
- final Matrix expected = new Matrix(canvas.getMatrix());
+ @Test
+ public void testScaleToCanvasMaxSize() {
+ final Canvas canvas = new Canvas();
+ final Matrix expected = new Matrix(canvas.getMatrix());
- Bitmap mockBitmapCache = Bitmap.createBitmap(2049, 1152, Bitmap.Config.ALPHA_8);
+ Bitmap mockBitmapCache = Bitmap.createBitmap(2049, 1152, Bitmap.Config.ALPHA_8);
- final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
- drawable.setBounds(0, 0, 1366, 768); // original viewbox size
- drawable.scaleCanvasToBounds(canvas, mockBitmapCache, drawable.getBounds());
+ final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
+ drawable.setBounds(0, 0, 1366, 768); // original viewbox size
+ drawable.scaleCanvasToBounds(canvas, mockBitmapCache, drawable.getBounds());
- expected.postScale(1 / 1.5f, 1 / 1.5f);
- expected.postTranslate(0f, 0f);
+ expected.postScale(1 / 1.5f, 1 / 1.5f);
+ expected.postTranslate(0f, 0f);
- assertEquals("Matrices should match", expected, canvas.getMatrix());
- }
+ assertEquals("Matrices should match", expected, canvas.getMatrix());
+ }
- @Test
- public void testMemoryAllocation() {
- Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
- Debug.getMemoryInfo(memoryInfo);
- final long memoryBefore = memoryInfo.getTotalPss(); // Get memory usage in KB
+ @Test
+ public void testMemoryAllocation() {
+ Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
+ Debug.getMemoryInfo(memoryInfo);
+ final long memoryBefore = memoryInfo.getTotalPss(); // Get memory usage in KB
- final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
- drawable.setBounds(0, 0, 1366, 768);
- drawable.createBitmapCache(2049, 1152);
+ final GlifPatternDrawable drawable = new GlifPatternDrawable(Color.RED);
+ drawable.setBounds(0, 0, 1366, 768);
+ drawable.createBitmapCache(2049, 1152);
- Debug.getMemoryInfo(memoryInfo);
- final long memoryAfter = memoryInfo.getTotalPss();
- Log.i(TAG, "Memory allocated for bitmap cache: " + (memoryAfter - memoryBefore));
- assertTrue("Memory allocation should not exceed 5MB", memoryAfter < memoryBefore + 5000);
- }
+ Debug.getMemoryInfo(memoryInfo);
+ final long memoryAfter = memoryInfo.getTotalPss();
+ Log.i(TAG, "Memory allocated for bitmap cache: " + (memoryAfter - memoryBefore));
+ assertTrue("Memory allocation should not exceed 5MB", memoryAfter < memoryBefore + 5000);
+ }
- private void assertSameColor(String message, int expected, int actual) {
- try {
- assertEquals(expected, actual);
- } catch (AssertionFailedError e) {
- throw new AssertionFailedError(message + " expected <#" + Integer.toHexString(expected)
- + "> but found <#" + Integer.toHexString(actual) + "> instead");
- }
+ private void assertSameColor(String message, int expected, int actual) {
+ try {
+ assertEquals(expected, actual);
+ } catch (AssertionFailedError e) {
+ throw new AssertionFailedError(
+ message
+ + " expected <#"
+ + Integer.toHexString(expected)
+ + "> but found <#"
+ + Integer.toHexString(actual)
+ + "> instead");
}
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/IllustrationTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/IllustrationTest.java
index a4b6f27..253893e 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/IllustrationTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/IllustrationTest.java
@@ -23,13 +23,11 @@ import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.view.View;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-
import com.android.setupwizardlib.view.Illustration;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,28 +35,29 @@ import org.junit.runner.RunWith;
@SmallTest
public class IllustrationTest {
- @Test
- public void testWillDraw() {
- final Illustration illustration = new Illustration(InstrumentationRegistry.getContext());
- assertFalse("The illustration needs to be drawn", illustration.willNotDraw());
- }
-
- @Test
- public void testAspectRatio() {
- final Context context = InstrumentationRegistry.getContext();
- // Force the context to be xhdpi
- context.getResources().getDisplayMetrics().density = 2.0f;
-
- final Illustration illustration = new Illustration(context);
- illustration.setAspectRatio(3.0f);
- final Drawable backgroundDrawable = new ColorDrawable(Color.RED);
- final Drawable illustrationDrawable = new ColorDrawable(Color.BLUE);
- illustration.setBackgroundDrawable(backgroundDrawable);
- illustration.setIllustration(illustrationDrawable);
-
- illustration.measure(View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
- // (300px / 3) round down to nearest mod (8dp = 16px) = 96px
- assertEquals("Top padding should be 96", 96, illustration.getPaddingTop());
- }
+ @Test
+ public void testWillDraw() {
+ final Illustration illustration = new Illustration(InstrumentationRegistry.getContext());
+ assertFalse("The illustration needs to be drawn", illustration.willNotDraw());
+ }
+
+ @Test
+ public void testAspectRatio() {
+ final Context context = InstrumentationRegistry.getContext();
+ // Force the context to be xhdpi
+ context.getResources().getDisplayMetrics().density = 2.0f;
+
+ final Illustration illustration = new Illustration(context);
+ illustration.setAspectRatio(3.0f);
+ final Drawable backgroundDrawable = new ColorDrawable(Color.RED);
+ final Drawable illustrationDrawable = new ColorDrawable(Color.BLUE);
+ illustration.setBackgroundDrawable(backgroundDrawable);
+ illustration.setIllustration(illustrationDrawable);
+
+ illustration.measure(
+ View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
+ // (300px / 3) round down to nearest mod (8dp = 16px) = 96px
+ assertEquals("Top padding should be 96", 96, illustration.getPaddingTop());
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemAdapterTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemAdapterTest.java
index e5875e4..63180dc 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemAdapterTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemAdapterTest.java
@@ -24,78 +24,74 @@ import static org.mockito.Mockito.mock;
import android.database.DataSetObserver;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-
import com.android.setupwizardlib.items.Item;
import com.android.setupwizardlib.items.ItemAdapter;
import com.android.setupwizardlib.items.ItemGroup;
import com.android.setupwizardlib.items.ItemHierarchy;
-
+import java.util.Arrays;
+import java.util.HashSet;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
-import java.util.Arrays;
-import java.util.HashSet;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ItemAdapterTest {
- private Item[] mItems = new Item[5];
- private ItemGroup mItemGroup = new ItemGroup();
-
- @Before
- public void setUp() throws Exception {
- for (int i = 0; i < 5; i++) {
- Item item = new Item();
- item.setTitle("TestTitle" + i);
- item.setId(i);
- item.setLayoutResource(((i % 3) + 1) * 10);
- mItems[i] = item;
- mItemGroup.addChild(item);
- }
- }
-
- @Test
- public void testAdapter() {
- ItemAdapter adapter = new ItemAdapter(mItemGroup);
- assertEquals("Adapter should have 5 items", 5, adapter.getCount());
- assertEquals("Adapter should return the first item", mItems[0], adapter.getItem(0));
- assertEquals("ID should be same as position", 2, adapter.getItemId(2));
-
- // Each test item has its own layout resource, and therefore its own view type
- assertEquals("Should have 3 different view types", 3, adapter.getViewTypeCount());
- HashSet<Integer> viewTypes = new HashSet<>(3);
- viewTypes.add(adapter.getItemViewType(0));
- viewTypes.add(adapter.getItemViewType(1));
- viewTypes.add(adapter.getItemViewType(2));
-
- assertEquals("View types should be 0, 1, 2",
- new HashSet<>(Arrays.asList(0, 1, 2)), viewTypes);
- }
-
- @Test
- public void testGetRootItemHierarchy() {
- ItemAdapter adapter = new ItemAdapter(mItemGroup);
- ItemHierarchy root = adapter.getRootItemHierarchy();
- assertSame("Root item hierarchy should be mItemGroup", mItemGroup, root);
- }
-
- @Test
- public void testAdapterNotifications() {
- ItemAdapter adapter = new ItemAdapter(mItemGroup);
- final DataSetObserver observer = mock(DataSetObserver.class);
- adapter.registerDataSetObserver(observer);
- final InOrder inOrder = inOrder(observer);
-
- mItems[0].setTitle("Child 1");
- inOrder.verify(observer).onChanged();
-
- mItemGroup.removeChild(mItems[1]);
- inOrder.verify(observer).onChanged();
-
- mItemGroup.addChild(mItems[1]);
- inOrder.verify(observer).onChanged();
+ private Item[] mItems = new Item[5];
+ private ItemGroup mItemGroup = new ItemGroup();
+
+ @Before
+ public void setUp() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ Item item = new Item();
+ item.setTitle("TestTitle" + i);
+ item.setId(i);
+ item.setLayoutResource(((i % 3) + 1) * 10);
+ mItems[i] = item;
+ mItemGroup.addChild(item);
}
+ }
+
+ @Test
+ public void testAdapter() {
+ ItemAdapter adapter = new ItemAdapter(mItemGroup);
+ assertEquals("Adapter should have 5 items", 5, adapter.getCount());
+ assertEquals("Adapter should return the first item", mItems[0], adapter.getItem(0));
+ assertEquals("ID should be same as position", 2, adapter.getItemId(2));
+
+ // Each test item has its own layout resource, and therefore its own view type
+ assertEquals("Should have 3 different view types", 3, adapter.getViewTypeCount());
+ HashSet<Integer> viewTypes = new HashSet<>(3);
+ viewTypes.add(adapter.getItemViewType(0));
+ viewTypes.add(adapter.getItemViewType(1));
+ viewTypes.add(adapter.getItemViewType(2));
+
+ assertEquals("View types should be 0, 1, 2", new HashSet<>(Arrays.asList(0, 1, 2)), viewTypes);
+ }
+
+ @Test
+ public void testGetRootItemHierarchy() {
+ ItemAdapter adapter = new ItemAdapter(mItemGroup);
+ ItemHierarchy root = adapter.getRootItemHierarchy();
+ assertSame("Root item hierarchy should be mItemGroup", mItemGroup, root);
+ }
+
+ @Test
+ public void testAdapterNotifications() {
+ ItemAdapter adapter = new ItemAdapter(mItemGroup);
+ final DataSetObserver observer = mock(DataSetObserver.class);
+ adapter.registerDataSetObserver(observer);
+ final InOrder inOrder = inOrder(observer);
+
+ mItems[0].setTitle("Child 1");
+ inOrder.verify(observer).onChanged();
+
+ mItemGroup.removeChild(mItems[1]);
+ inOrder.verify(observer).onChanged();
+
+ mItemGroup.addChild(mItems[1]);
+ inOrder.verify(observer).onChanged();
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemInflaterTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemInflaterTest.java
index 20fd2cc..9e96bae 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemInflaterTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemInflaterTest.java
@@ -22,12 +22,10 @@ import static org.junit.Assert.assertTrue;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-
import com.android.setupwizardlib.items.Item;
import com.android.setupwizardlib.items.ItemGroup;
import com.android.setupwizardlib.items.ItemHierarchy;
import com.android.setupwizardlib.items.ItemInflater;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,25 +33,26 @@ import org.junit.runner.RunWith;
@SmallTest
public class ItemInflaterTest {
- @Test
- public void testDefaultPackage() {
- ItemInflater inflater = new ItemInflater(InstrumentationRegistry.getContext());
- assertEquals("Default package should be the one containing Item class",
- "com.android.setupwizardlib.items.", inflater.getDefaultPackage());
- }
-
- @Test
- public void testInflate() {
- ItemInflater inflater = new ItemInflater(InstrumentationRegistry.getContext());
- ItemHierarchy item = inflater.inflate(R.xml.test_items);
- assertTrue("Inflated item should be ItemGroup", item instanceof ItemGroup);
- ItemGroup itemGroup = (ItemGroup) item;
-
- Item child0 = (Item) itemGroup.getItemAt(0);
- Item child1 = (Item) itemGroup.getItemAt(1);
- assertEquals("Title of first child should be Title1", "Title1", child0.getTitle());
- assertEquals("ID of second child should be test_item_2", R.id.test_item_2, child1.getId());
- assertEquals("Summary of second child should be Summary2", "Summary2",
- child1.getSummary());
- }
+ @Test
+ public void testDefaultPackage() {
+ ItemInflater inflater = new ItemInflater(InstrumentationRegistry.getContext());
+ assertEquals(
+ "Default package should be the one containing Item class",
+ "com.android.setupwizardlib.items.",
+ inflater.getDefaultPackage());
+ }
+
+ @Test
+ public void testInflate() {
+ ItemInflater inflater = new ItemInflater(InstrumentationRegistry.getContext());
+ ItemHierarchy item = inflater.inflate(R.xml.test_items);
+ assertTrue("Inflated item should be ItemGroup", item instanceof ItemGroup);
+ ItemGroup itemGroup = (ItemGroup) item;
+
+ Item child0 = (Item) itemGroup.getItemAt(0);
+ Item child1 = (Item) itemGroup.getItemAt(1);
+ assertEquals("Title of first child should be Title1", "Title1", child0.getTitle());
+ assertEquals("ID of second child should be test_item_2", R.id.test_item_2, child1.getId());
+ assertEquals("Summary of second child should be Summary2", "Summary2", child1.getSummary());
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemLayoutTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemLayoutTest.java
index 85876b4..dbf71b2 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemLayoutTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemLayoutTest.java
@@ -17,26 +17,22 @@
package com.android.setupwizardlib.test;
import static android.support.test.InstrumentationRegistry.getTargetContext;
-
import static org.junit.Assert.assertNotNull;
import android.content.Context;
-import android.support.test.filters.SmallTest;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.widget.FrameLayout;
-
+import android.support.test.filters.SmallTest;
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.items.Item;
-
+import java.util.ArrayList;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Sanity test for all the item layouts to make sure they won't crash when being inflated in
* different themes.
@@ -45,50 +41,50 @@ import java.util.List;
@SmallTest
public class ItemLayoutTest {
- @Parameters
- public static Iterable<Object[]> data() {
- int[] themes = new int[] {
- R.style.SuwThemeMaterial_Light,
- R.style.SuwThemeMaterial,
- R.style.SuwThemeGlif_Light,
- R.style.SuwThemeGlif,
- R.style.SuwThemeGlifV2_Light,
- R.style.SuwThemeGlifV2
+ @Parameters
+ public static Iterable<Object[]> data() {
+ int[] themes =
+ new int[] {
+ R.style.SuwThemeMaterial_Light,
+ R.style.SuwThemeMaterial,
+ R.style.SuwThemeGlif_Light,
+ R.style.SuwThemeGlif,
+ R.style.SuwThemeGlifV2_Light,
+ R.style.SuwThemeGlifV2
};
- int[] layouts = new int[] {
- R.layout.suw_items_default,
- R.layout.suw_items_verbose,
- R.layout.suw_items_description
+ int[] layouts =
+ new int[] {
+ R.layout.suw_items_default, R.layout.suw_items_verbose, R.layout.suw_items_description
};
- // Test all the possible combinations of themes and layouts.
- List<Object[]> params = new ArrayList<>();
- for (int theme : themes) {
- for (int layout : layouts) {
- params.add(new Object[] { theme, layout });
- }
- }
- return params;
+ // Test all the possible combinations of themes and layouts.
+ List<Object[]> params = new ArrayList<>();
+ for (int theme : themes) {
+ for (int layout : layouts) {
+ params.add(new Object[] {theme, layout});
+ }
}
+ return params;
+ }
- private final Context mContext;
- private final FrameLayout mParent;
- private final Item mItem;
+ private final Context mContext;
+ private final FrameLayout mParent;
+ private final Item mItem;
- public ItemLayoutTest(int theme, int layout) {
- mContext = new ContextThemeWrapper(getTargetContext(), theme);
- mParent = new FrameLayout(mContext);
- mItem = new Item();
- mItem.setLayoutResource(layout);
- }
+ public ItemLayoutTest(int theme, int layout) {
+ mContext = new ContextThemeWrapper(getTargetContext(), theme);
+ mParent = new FrameLayout(mContext);
+ mItem = new Item();
+ mItem.setLayoutResource(layout);
+ }
- @Test
- public void testInflateLayoutHasBasicViews() {
- LayoutInflater.from(mContext).inflate(mItem.getLayoutResource(), mParent, true);
- mItem.onBindView(mParent);
+ @Test
+ public void testInflateLayoutHasBasicViews() {
+ LayoutInflater.from(mContext).inflate(mItem.getLayoutResource(), mParent, true);
+ mItem.onBindView(mParent);
- assertNotNull("Title should exist", mParent.findViewById(R.id.suw_items_title));
- assertNotNull("Summary should exist", mParent.findViewById(R.id.suw_items_summary));
- assertNotNull("Icon should exist", mParent.findViewById(R.id.suw_items_icon));
- }
+ assertNotNull("Title should exist", mParent.findViewById(R.id.suw_items_title));
+ assertNotNull("Summary should exist", mParent.findViewById(R.id.suw_items_summary));
+ assertNotNull("Icon should exist", mParent.findViewById(R.id.suw_items_icon));
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemTest.java
index b4ebabb..84990dd 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/ItemTest.java
@@ -28,19 +28,17 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.items.Item;
import com.android.setupwizardlib.items.ItemHierarchy.Observer;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,149 +50,149 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class ItemTest {
- private TextView mTitleView;
- private TextView mSummaryView;
- private ImageView mIconView;
- private FrameLayout mIconContainer;
-
- @Mock
- private Observer mObserver;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testOnBindView() {
- Item item = new Item();
- item.setTitle("TestTitle");
- item.setSummary("TestSummary");
- Drawable icon = new ShapeDrawable();
- icon.setLevel(4);
- item.setIcon(icon);
- View view = createLayout();
-
- mIconView.setImageLevel(1);
- Drawable recycledIcon = new ShapeDrawable();
- mIconView.setImageDrawable(recycledIcon);
-
- item.onBindView(view);
-
- assertEquals("Title should be \"TestTitle\"", "TestTitle", mTitleView.getText().toString());
- assertEquals("Summary should be \"TestSummary\"", "TestSummary",
- mSummaryView.getText().toString());
- assertSame("Icon should be the icon shape drawable", icon, mIconView.getDrawable());
- assertEquals("Recycled icon level should not change", 1, recycledIcon.getLevel());
- assertEquals("Icon should be level 4", 4, icon.getLevel());
- }
-
- @Test
- public void testSingleLineItem() {
- Item item = new Item();
- item.setTitle("TestTitle");
- View view = createLayout();
-
- item.onBindView(view);
-
- assertEquals("Title should be \"TestTitle\"", "TestTitle", mTitleView.getText().toString());
- assertEquals("Summary should be gone", View.GONE, mSummaryView.getVisibility());
- assertEquals("IconContainer should be gone", View.GONE, mIconContainer.getVisibility());
- }
-
- @Test
- public void testProperties() {
- Item item = new Item();
- item.registerObserver(mObserver);
- final InOrder inOrder = inOrder(mObserver);
-
- item.setTitle("TestTitle");
- inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
-
- item.setSummary("TestSummary");
- inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
-
- item.setEnabled(false);
- inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
-
- ShapeDrawable icon = new ShapeDrawable();
- item.setIcon(icon);
- inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
-
- item.setId(12345);
-
- item.setLayoutResource(56789);
- inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
-
- assertEquals("Title should be \"TestTitle\"", "TestTitle", item.getTitle());
- assertEquals("Summary should be \"TestSummary\"", "TestSummary", item.getSummary());
- assertFalse("Enabled should be false", item.isEnabled());
- assertSame("Icon should be same as set", icon, item.getIcon());
- assertEquals("ID should be 12345", 12345, item.getId());
- assertEquals("Layout resource should be 56789", 56789, item.getLayoutResource());
- }
-
- @Test
- public void testDefaultValues() {
- Item item = new Item();
-
- assertNull("Default title should be null", item.getTitle());
- assertNull("Default summary should be null", item.getSummary());
- assertNull("Default icon should be null", item.getIcon());
- assertTrue("Default enabled should be true", item.isEnabled());
- assertEquals("Default ID should be 0", 0, item.getId());
- assertEquals("Default layout resource should be R.layout.suw_items_text",
- R.layout.suw_items_default, item.getLayoutResource());
- assertTrue("Default visible should be true", item.isVisible());
- }
-
- @Test
- public void testHierarchyImplementation() {
- Item item = new Item();
- item.setId(12345);
-
- assertEquals("getCount should be 1", 1, item.getCount());
- assertSame("getItemAt should return itself", item, item.getItemAt(0));
- assertSame("findItemById with same ID should return itself", item,
- item.findItemById(12345));
- assertNull("findItemById with different ID should return null", item.findItemById(34567));
- }
-
- @Test
- public void testVisible() {
- Item item = new Item();
- item.registerObserver(mObserver);
- item.setVisible(false);
-
- assertFalse("Item should not be visible", item.isVisible());
- assertEquals("Item count should be 0 when not visible", 0, item.getCount());
-
- verify(mObserver).onItemRangeRemoved(eq(item), eq(0), eq(1));
-
- item.setVisible(true);
- verify(mObserver).onItemRangeInserted(eq(item), eq(0), eq(1));
- }
-
- private ViewGroup createLayout() {
- Context context = InstrumentationRegistry.getContext();
- ViewGroup root = new FrameLayout(context);
-
- mTitleView = new TextView(context);
- mTitleView.setId(R.id.suw_items_title);
- root.addView(mTitleView);
-
- mSummaryView = new TextView(context);
- mSummaryView.setId(R.id.suw_items_summary);
- root.addView(mSummaryView);
-
- mIconContainer = new FrameLayout(context);
- mIconContainer.setId(R.id.suw_items_icon_container);
- root.addView(mIconContainer);
-
- mIconView = new ImageView(context);
- mIconView.setId(R.id.suw_items_icon);
- mIconContainer.addView(mIconView);
-
- return root;
- }
+ private TextView mTitleView;
+ private TextView mSummaryView;
+ private ImageView mIconView;
+ private FrameLayout mIconContainer;
+
+ @Mock private Observer mObserver;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testOnBindView() {
+ Item item = new Item();
+ item.setTitle("TestTitle");
+ item.setSummary("TestSummary");
+ Drawable icon = new ShapeDrawable();
+ icon.setLevel(4);
+ item.setIcon(icon);
+ View view = createLayout();
+
+ mIconView.setImageLevel(1);
+ Drawable recycledIcon = new ShapeDrawable();
+ mIconView.setImageDrawable(recycledIcon);
+
+ item.onBindView(view);
+
+ assertEquals("Title should be \"TestTitle\"", "TestTitle", mTitleView.getText().toString());
+ assertEquals(
+ "Summary should be \"TestSummary\"", "TestSummary", mSummaryView.getText().toString());
+ assertSame("Icon should be the icon shape drawable", icon, mIconView.getDrawable());
+ assertEquals("Recycled icon level should not change", 1, recycledIcon.getLevel());
+ assertEquals("Icon should be level 4", 4, icon.getLevel());
+ }
+
+ @Test
+ public void testSingleLineItem() {
+ Item item = new Item();
+ item.setTitle("TestTitle");
+ View view = createLayout();
+
+ item.onBindView(view);
+
+ assertEquals("Title should be \"TestTitle\"", "TestTitle", mTitleView.getText().toString());
+ assertEquals("Summary should be gone", View.GONE, mSummaryView.getVisibility());
+ assertEquals("IconContainer should be gone", View.GONE, mIconContainer.getVisibility());
+ }
+
+ @Test
+ public void testProperties() {
+ Item item = new Item();
+ item.registerObserver(mObserver);
+ final InOrder inOrder = inOrder(mObserver);
+
+ item.setTitle("TestTitle");
+ inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
+
+ item.setSummary("TestSummary");
+ inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
+
+ item.setEnabled(false);
+ inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
+
+ ShapeDrawable icon = new ShapeDrawable();
+ item.setIcon(icon);
+ inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
+
+ item.setId(12345);
+
+ item.setLayoutResource(56789);
+ inOrder.verify(mObserver).onItemRangeChanged(eq(item), eq(0), eq(1));
+
+ assertEquals("Title should be \"TestTitle\"", "TestTitle", item.getTitle());
+ assertEquals("Summary should be \"TestSummary\"", "TestSummary", item.getSummary());
+ assertFalse("Enabled should be false", item.isEnabled());
+ assertSame("Icon should be same as set", icon, item.getIcon());
+ assertEquals("ID should be 12345", 12345, item.getId());
+ assertEquals("Layout resource should be 56789", 56789, item.getLayoutResource());
+ }
+
+ @Test
+ public void testDefaultValues() {
+ Item item = new Item();
+
+ assertNull("Default title should be null", item.getTitle());
+ assertNull("Default summary should be null", item.getSummary());
+ assertNull("Default icon should be null", item.getIcon());
+ assertTrue("Default enabled should be true", item.isEnabled());
+ assertEquals("Default ID should be 0", 0, item.getId());
+ assertEquals(
+ "Default layout resource should be R.layout.suw_items_text",
+ R.layout.suw_items_default,
+ item.getLayoutResource());
+ assertTrue("Default visible should be true", item.isVisible());
+ }
+
+ @Test
+ public void testHierarchyImplementation() {
+ Item item = new Item();
+ item.setId(12345);
+
+ assertEquals("getCount should be 1", 1, item.getCount());
+ assertSame("getItemAt should return itself", item, item.getItemAt(0));
+ assertSame("findItemById with same ID should return itself", item, item.findItemById(12345));
+ assertNull("findItemById with different ID should return null", item.findItemById(34567));
+ }
+
+ @Test
+ public void testVisible() {
+ Item item = new Item();
+ item.registerObserver(mObserver);
+ item.setVisible(false);
+
+ assertFalse("Item should not be visible", item.isVisible());
+ assertEquals("Item count should be 0 when not visible", 0, item.getCount());
+
+ verify(mObserver).onItemRangeRemoved(eq(item), eq(0), eq(1));
+
+ item.setVisible(true);
+ verify(mObserver).onItemRangeInserted(eq(item), eq(0), eq(1));
+ }
+
+ private ViewGroup createLayout() {
+ Context context = InstrumentationRegistry.getContext();
+ ViewGroup root = new FrameLayout(context);
+
+ mTitleView = new TextView(context);
+ mTitleView.setId(R.id.suw_items_title);
+ root.addView(mTitleView);
+
+ mSummaryView = new TextView(context);
+ mSummaryView.setId(R.id.suw_items_summary);
+ root.addView(mSummaryView);
+
+ mIconContainer = new FrameLayout(context);
+ mIconContainer.setId(R.id.suw_items_icon_container);
+ root.addView(mIconContainer);
+
+ mIconView = new ImageView(context);
+ mIconView.setId(R.id.suw_items_icon);
+ mIconContainer.addView(mIconView);
+
+ return root;
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/ReflectionInflaterTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/ReflectionInflaterTest.java
index 137a146..69e5882 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/ReflectionInflaterTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/ReflectionInflaterTest.java
@@ -20,64 +20,59 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.annotation.NonNull;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
-
-import androidx.annotation.NonNull;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.items.ReflectionInflater;
-
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ReflectionInflaterTest {
- @Test
- public void testInflateXml() {
- final Context context = InstrumentationRegistry.getContext();
- TestInflater inflater = new TestInflater(context);
- final Animation result = inflater.inflate(R.xml.reflection_inflater_test);
+ @Test
+ public void testInflateXml() {
+ final Context context = InstrumentationRegistry.getContext();
+ TestInflater inflater = new TestInflater(context);
+ final Animation result = inflater.inflate(R.xml.reflection_inflater_test);
- assertTrue(result instanceof AnimationSet);
- final AnimationSet set = (AnimationSet) result;
- final List<Animation> animations = set.getAnimations();
- assertEquals(1, animations.size());
- assertTrue(animations.get(0) instanceof ScaleAnimation);
- }
+ assertTrue(result instanceof AnimationSet);
+ final AnimationSet set = (AnimationSet) result;
+ final List<Animation> animations = set.getAnimations();
+ assertEquals(1, animations.size());
+ assertTrue(animations.get(0) instanceof ScaleAnimation);
+ }
- @Test
- public void testDefaultPackage() {
- final Context context = InstrumentationRegistry.getContext();
- TestInflater inflater = new TestInflater(context);
- inflater.setDefaultPackage("android.view.animation.");
- final Animation result =
- inflater.inflate(R.xml.reflection_inflater_test_with_default_package);
+ @Test
+ public void testDefaultPackage() {
+ final Context context = InstrumentationRegistry.getContext();
+ TestInflater inflater = new TestInflater(context);
+ inflater.setDefaultPackage("android.view.animation.");
+ final Animation result = inflater.inflate(R.xml.reflection_inflater_test_with_default_package);
- assertTrue(result instanceof AnimationSet);
- final AnimationSet set = (AnimationSet) result;
- final List<Animation> animations = set.getAnimations();
- assertEquals(1, animations.size());
- assertTrue(animations.get(0) instanceof ScaleAnimation);
- }
+ assertTrue(result instanceof AnimationSet);
+ final AnimationSet set = (AnimationSet) result;
+ final List<Animation> animations = set.getAnimations();
+ assertEquals(1, animations.size());
+ assertTrue(animations.get(0) instanceof ScaleAnimation);
+ }
- private static class TestInflater extends ReflectionInflater<Animation> {
+ private static class TestInflater extends ReflectionInflater<Animation> {
- protected TestInflater(@NonNull Context context) {
- super(context);
- }
+ protected TestInflater(@NonNull Context context) {
+ super(context);
+ }
- @Override
- protected void onAddChildItem(Animation parent, Animation child) {
- final AnimationSet group = (AnimationSet) parent;
- group.addAnimation(child);
- }
+ @Override
+ protected void onAddChildItem(Animation parent, Animation child) {
+ final AnimationSet group = (AnimationSet) parent;
+ group.addAnimation(child);
}
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardLayoutTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardLayoutTest.java
index 531d69e..9d2f784 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardLayoutTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardLayoutTest.java
@@ -27,9 +27,7 @@ import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.annotation.IdRes;
import android.util.SparseArray;
import android.view.AbsSavedState;
import android.view.ContextThemeWrapper;
@@ -37,15 +35,14 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
-
-import androidx.annotation.IdRes;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.SetupWizardLayout;
import com.android.setupwizardlib.template.HeaderMixin;
import com.android.setupwizardlib.template.NavigationBarMixin;
import com.android.setupwizardlib.template.ProgressBarMixin;
import com.android.setupwizardlib.view.NavigationBar;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,191 +51,196 @@ import org.junit.runner.RunWith;
@SmallTest
public class SetupWizardLayoutTest {
- @IdRes
- private static final int ID1234 = 1234;
-
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeMaterial_Light);
- }
-
- @Test
- public void testDefaultTemplate() {
- SetupWizardLayout layout = new SetupWizardLayout(mContext);
- assertDefaultTemplateInflated(layout);
- }
-
- @Test
- public void testSetHeaderText() {
- SetupWizardLayout layout = new SetupWizardLayout(mContext);
- TextView title = (TextView) layout.findViewById(R.id.suw_layout_title);
- layout.setHeaderText("Abracadabra");
- assertEquals("Header text should be \"Abracadabra\"", "Abracadabra", title.getText());
- }
-
- @Test
- public void testAddView() {
- SetupWizardLayout layout = new SetupWizardLayout(mContext);
- TextView tv = new TextView(mContext);
- tv.setId(R.id.test_view_id);
- layout.addView(tv);
- assertDefaultTemplateInflated(layout);
- View view = layout.findViewById(R.id.test_view_id);
- assertSame("The view added should be the same text view", tv, view);
- }
-
- @Test
- public void testInflateFromXml() {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- SetupWizardLayout layout = (SetupWizardLayout) inflater.inflate(R.layout.test_layout, null);
- assertDefaultTemplateInflated(layout);
- View content = layout.findViewById(R.id.test_content);
- assertTrue("@id/test_content should be a TextView", content instanceof TextView);
- }
-
- @Test
- public void testCustomTemplate() {
- SetupWizardLayout layout = new SetupWizardLayout(mContext, R.layout.test_template);
- View templateView = layout.findViewById(R.id.test_template_view);
- assertNotNull("@id/test_template_view should exist in template", templateView);
-
- TextView tv = new TextView(mContext);
- tv.setId(R.id.test_view_id);
- layout.addView(tv);
-
- templateView = layout.findViewById(R.id.test_template_view);
- assertNotNull("@id/test_template_view should exist in template", templateView);
- View contentView = layout.findViewById(R.id.test_view_id);
- assertSame("The view added should be the same text view", tv, contentView);
-
- // The following methods should be no-ops because the custom template doesn't contain the
- // corresponding optional views. Just check that they don't throw exceptions.
- layout.setHeaderText("Abracadabra");
- layout.setIllustration(new ColorDrawable(Color.MAGENTA));
- layout.setLayoutBackground(new ColorDrawable(Color.RED));
- }
-
- @Test
- public void testGetNavigationBar() {
- final SetupWizardLayout layout = new SetupWizardLayout(mContext);
- final NavigationBar navigationBar = layout.getNavigationBar();
- assertEquals("Navigation bar should have ID = @id/suw_layout_navigation_bar",
- R.id.suw_layout_navigation_bar, navigationBar.getId());
- }
-
- @Test
- public void testGetNavigationBarNull() {
- // test_template does not have navigation bar so getNavigationBar() should return null.
- final SetupWizardLayout layout = new SetupWizardLayout(mContext, R.layout.test_template);
- final NavigationBar navigationBar = layout.getNavigationBar();
- assertNull("getNavigationBar() in test_template should return null", navigationBar);
- }
-
- @Test
- public void testShowProgressBar() {
- final SetupWizardLayout layout = new SetupWizardLayout(mContext);
- layout.showProgressBar();
- assertTrue("Progress bar should be shown", layout.isProgressBarShown());
- final View progressBar = layout.findViewById(R.id.suw_layout_progress);
- assertTrue("Progress bar view should be shown",
- progressBar instanceof ProgressBar && progressBar.getVisibility() == View.VISIBLE);
- }
-
- @Test
- public void testHideProgressBar() {
- final SetupWizardLayout layout = new SetupWizardLayout(mContext);
- layout.showProgressBar();
- assertTrue("Progress bar should be shown", layout.isProgressBarShown());
- layout.hideProgressBar();
- assertFalse("Progress bar should be hidden", layout.isProgressBarShown());
- final View progressBar = layout.findViewById(R.id.suw_layout_progress);
- assertTrue("Progress bar view should exist",
- progressBar == null || progressBar.getVisibility() != View.VISIBLE);
- }
-
- @Test
- public void testShowProgressBarNotExist() {
- // test_template does not have progress bar, so showNavigationBar() should do nothing.
- final SetupWizardLayout layout = new SetupWizardLayout(mContext, R.layout.test_template);
- layout.showProgressBar();
- assertFalse("Progress bar should not be shown", layout.isProgressBarShown());
- }
-
- @Test
- public void testNonMaterialTheme() {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- android.R.style.Theme);
- new SetupWizardLayout(mContext);
- // Inflating with a non-Material theme should not crash
- }
-
- @Test
- public void testOnRestoreFromInstanceState() {
- final SetupWizardLayout layout = new SetupWizardLayout(mContext);
- layout.setId(ID1234);
-
- SparseArray<Parcelable> container = new SparseArray<>();
- layout.saveHierarchyState(container);
-
- final SetupWizardLayout layout2 = new SetupWizardLayout(mContext);
- layout2.setId(ID1234);
- layout2.restoreHierarchyState(container);
-
- assertFalse("Progress bar should not be shown", layout2.isProgressBarShown());
- }
-
- @Test
- public void testOnRestoreFromInstanceStateProgressBarShown() {
- final SetupWizardLayout layout = new SetupWizardLayout(mContext);
- layout.setId(ID1234);
-
- layout.setProgressBarShown(true);
-
- SparseArray<Parcelable> container = new SparseArray<>();
- layout.saveHierarchyState(container);
-
- final SetupWizardLayout layout2 = new SetupWizardLayout(mContext);
- layout2.setId(ID1234);
- layout2.restoreHierarchyState(container);
-
- assertTrue("Progress bar should be shown", layout2.isProgressBarShown());
- }
-
- @Test
- public void testOnRestoreFromIncompatibleInstanceState() {
- final SetupWizardLayout layout = new SetupWizardLayout(mContext);
- layout.setId(ID1234);
-
- SparseArray<Parcelable> container = new SparseArray<>();
- container.put(1234, AbsSavedState.EMPTY_STATE);
- layout.restoreHierarchyState(container);
-
- // SetupWizardLayout shouldn't crash with incompatible Parcelable
-
- assertFalse("Progress bar should not be shown", layout.isProgressBarShown());
- }
-
- @Test
- public void testGetMixins() {
- final SetupWizardLayout layout = new SetupWizardLayout(mContext);
- assertNotNull("SetupWizardLayout should have header mixin",
- layout.getMixin(HeaderMixin.class));
- assertNotNull("SetupWizardLayout should have progress bar mixin",
- layout.getMixin(ProgressBarMixin.class));
- assertNotNull("SetupWizardLayout should have navigation bar mixin",
- layout.getMixin(NavigationBarMixin.class));
- }
-
- private void assertDefaultTemplateInflated(SetupWizardLayout layout) {
- View decorView = layout.findViewById(R.id.suw_layout_decor);
- View navbar = layout.findViewById(R.id.suw_layout_navigation_bar);
- View title = layout.findViewById(R.id.suw_layout_title);
- assertNotNull("@id/suw_layout_decor_view should not be null", decorView);
- assertTrue("@id/suw_layout_navigation_bar should be an instance of NavigationBar",
- navbar instanceof NavigationBar);
- assertNotNull("@id/suw_layout_title should not be null", title);
- }
+ @IdRes private static final int ID1234 = 1234;
+
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext =
+ new ContextThemeWrapper(
+ InstrumentationRegistry.getContext(), R.style.SuwThemeMaterial_Light);
+ }
+
+ @Test
+ public void testDefaultTemplate() {
+ SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ assertDefaultTemplateInflated(layout);
+ }
+
+ @Test
+ public void testSetHeaderText() {
+ SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ TextView title = (TextView) layout.findViewById(R.id.suw_layout_title);
+ layout.setHeaderText("Abracadabra");
+ assertEquals("Header text should be \"Abracadabra\"", "Abracadabra", title.getText());
+ }
+
+ @Test
+ public void testAddView() {
+ SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ TextView tv = new TextView(mContext);
+ tv.setId(R.id.test_view_id);
+ layout.addView(tv);
+ assertDefaultTemplateInflated(layout);
+ View view = layout.findViewById(R.id.test_view_id);
+ assertSame("The view added should be the same text view", tv, view);
+ }
+
+ @Test
+ public void testInflateFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ SetupWizardLayout layout = (SetupWizardLayout) inflater.inflate(R.layout.test_layout, null);
+ assertDefaultTemplateInflated(layout);
+ View content = layout.findViewById(R.id.test_content);
+ assertTrue("@id/test_content should be a TextView", content instanceof TextView);
+ }
+
+ @Test
+ public void testCustomTemplate() {
+ SetupWizardLayout layout = new SetupWizardLayout(mContext, R.layout.test_template);
+ View templateView = layout.findViewById(R.id.test_template_view);
+ assertNotNull("@id/test_template_view should exist in template", templateView);
+
+ TextView tv = new TextView(mContext);
+ tv.setId(R.id.test_view_id);
+ layout.addView(tv);
+
+ templateView = layout.findViewById(R.id.test_template_view);
+ assertNotNull("@id/test_template_view should exist in template", templateView);
+ View contentView = layout.findViewById(R.id.test_view_id);
+ assertSame("The view added should be the same text view", tv, contentView);
+
+ // The following methods should be no-ops because the custom template doesn't contain the
+ // corresponding optional views. Just check that they don't throw exceptions.
+ layout.setHeaderText("Abracadabra");
+ layout.setIllustration(new ColorDrawable(Color.MAGENTA));
+ layout.setLayoutBackground(new ColorDrawable(Color.RED));
+ }
+
+ @Test
+ public void testGetNavigationBar() {
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ final NavigationBar navigationBar = layout.getNavigationBar();
+ assertEquals(
+ "Navigation bar should have ID = @id/suw_layout_navigation_bar",
+ R.id.suw_layout_navigation_bar,
+ navigationBar.getId());
+ }
+
+ @Test
+ public void testGetNavigationBarNull() {
+ // test_template does not have navigation bar so getNavigationBar() should return null.
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext, R.layout.test_template);
+ final NavigationBar navigationBar = layout.getNavigationBar();
+ assertNull("getNavigationBar() in test_template should return null", navigationBar);
+ }
+
+ @Test
+ public void testShowProgressBar() {
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ layout.showProgressBar();
+ assertTrue("Progress bar should be shown", layout.isProgressBarShown());
+ final View progressBar = layout.findViewById(R.id.suw_layout_progress);
+ assertTrue(
+ "Progress bar view should be shown",
+ progressBar instanceof ProgressBar && progressBar.getVisibility() == View.VISIBLE);
+ }
+
+ @Test
+ public void testHideProgressBar() {
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ layout.showProgressBar();
+ assertTrue("Progress bar should be shown", layout.isProgressBarShown());
+ layout.hideProgressBar();
+ assertFalse("Progress bar should be hidden", layout.isProgressBarShown());
+ final View progressBar = layout.findViewById(R.id.suw_layout_progress);
+ assertTrue(
+ "Progress bar view should exist",
+ progressBar == null || progressBar.getVisibility() != View.VISIBLE);
+ }
+
+ @Test
+ public void testShowProgressBarNotExist() {
+ // test_template does not have progress bar, so showNavigationBar() should do nothing.
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext, R.layout.test_template);
+ layout.showProgressBar();
+ assertFalse("Progress bar should not be shown", layout.isProgressBarShown());
+ }
+
+ @Test
+ public void testNonMaterialTheme() {
+ mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(), android.R.style.Theme);
+ new SetupWizardLayout(mContext);
+ // Inflating with a non-Material theme should not crash
+ }
+
+ @Test
+ public void testOnRestoreFromInstanceState() {
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ layout.setId(ID1234);
+
+ SparseArray<Parcelable> container = new SparseArray<>();
+ layout.saveHierarchyState(container);
+
+ final SetupWizardLayout layout2 = new SetupWizardLayout(mContext);
+ layout2.setId(ID1234);
+ layout2.restoreHierarchyState(container);
+
+ assertFalse("Progress bar should not be shown", layout2.isProgressBarShown());
+ }
+
+ @Test
+ public void testOnRestoreFromInstanceStateProgressBarShown() {
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ layout.setId(ID1234);
+
+ layout.setProgressBarShown(true);
+
+ SparseArray<Parcelable> container = new SparseArray<>();
+ layout.saveHierarchyState(container);
+
+ final SetupWizardLayout layout2 = new SetupWizardLayout(mContext);
+ layout2.setId(ID1234);
+ layout2.restoreHierarchyState(container);
+
+ assertTrue("Progress bar should be shown", layout2.isProgressBarShown());
+ }
+
+ @Test
+ public void testOnRestoreFromIncompatibleInstanceState() {
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ layout.setId(ID1234);
+
+ SparseArray<Parcelable> container = new SparseArray<>();
+ container.put(1234, AbsSavedState.EMPTY_STATE);
+ layout.restoreHierarchyState(container);
+
+ // SetupWizardLayout shouldn't crash with incompatible Parcelable
+
+ assertFalse("Progress bar should not be shown", layout.isProgressBarShown());
+ }
+
+ @Test
+ public void testGetMixins() {
+ final SetupWizardLayout layout = new SetupWizardLayout(mContext);
+ assertNotNull("SetupWizardLayout should have header mixin", layout.getMixin(HeaderMixin.class));
+ assertNotNull(
+ "SetupWizardLayout should have progress bar mixin",
+ layout.getMixin(ProgressBarMixin.class));
+ assertNotNull(
+ "SetupWizardLayout should have navigation bar mixin",
+ layout.getMixin(NavigationBarMixin.class));
+ }
+
+ private void assertDefaultTemplateInflated(SetupWizardLayout layout) {
+ View decorView = layout.findViewById(R.id.suw_layout_decor);
+ View navbar = layout.findViewById(R.id.suw_layout_navigation_bar);
+ View title = layout.findViewById(R.id.suw_layout_title);
+ assertNotNull("@id/suw_layout_decor_view should not be null", decorView);
+ assertTrue(
+ "@id/suw_layout_navigation_bar should be an instance of NavigationBar",
+ navbar instanceof NavigationBar);
+ assertNotNull("@id/suw_layout_title should not be null", title);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardListLayoutTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardListLayoutTest.java
index 5c34fe0..fc18a31 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardListLayoutTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/SetupWizardListLayoutTest.java
@@ -25,20 +25,18 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
-
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.SetupWizardLayout;
import com.android.setupwizardlib.SetupWizardListLayout;
import com.android.setupwizardlib.view.NavigationBar;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,90 +45,93 @@ import org.junit.runner.RunWith;
@SmallTest
public class SetupWizardListLayoutTest {
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(InstrumentationRegistry.getContext(),
- R.style.SuwThemeMaterial_Light);
- }
-
- @Test
- public void testDefaultTemplate() {
- SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
- assertListTemplateInflated(layout);
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext =
+ new ContextThemeWrapper(
+ InstrumentationRegistry.getContext(), R.style.SuwThemeMaterial_Light);
+ }
+
+ @Test
+ public void testDefaultTemplate() {
+ SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
+ assertListTemplateInflated(layout);
+ }
+
+ @Test
+ public void testAddView() {
+ SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
+ TextView tv = new TextView(mContext);
+ try {
+ layout.addView(tv);
+ fail("Adding view to ListLayout should throw");
+ } catch (UnsupportedOperationException e) {
+ // Expected exception
}
-
- @Test
- public void testAddView() {
- SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
- TextView tv = new TextView(mContext);
- try {
- layout.addView(tv);
- fail("Adding view to ListLayout should throw");
- } catch (UnsupportedOperationException e) {
- // Expected exception
- }
- }
-
- @Test
- public void testInflateFromXml() {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- SetupWizardListLayout layout = (SetupWizardListLayout)
- inflater.inflate(R.layout.test_list_layout, null);
- assertListTemplateInflated(layout);
+ }
+
+ @Test
+ public void testInflateFromXml() {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ SetupWizardListLayout layout =
+ (SetupWizardListLayout) inflater.inflate(R.layout.test_list_layout, null);
+ assertListTemplateInflated(layout);
+ }
+
+ @Test
+ public void testShowProgressBar() {
+ final SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
+ layout.showProgressBar();
+ assertTrue("Progress bar should be shown", layout.isProgressBarShown());
+ final View progressBar = layout.findViewById(R.id.suw_layout_progress);
+ assertTrue(
+ "Progress bar view should be shown",
+ progressBar instanceof ProgressBar && progressBar.getVisibility() == View.VISIBLE);
+ }
+
+ @Test
+ public void testDividerInsetLegacy() {
+ SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
+ assertListTemplateInflated(layout);
- @Test
- public void testShowProgressBar() {
- final SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
- layout.showProgressBar();
- assertTrue("Progress bar should be shown", layout.isProgressBarShown());
- final View progressBar = layout.findViewById(R.id.suw_layout_progress);
- assertTrue("Progress bar view should be shown",
- progressBar instanceof ProgressBar && progressBar.getVisibility() == View.VISIBLE);
- }
-
- @Test
- public void testDividerInsetLegacy() {
- SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertListTemplateInflated(layout);
-
- layout.setDividerInset(10);
- assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
+ layout.setDividerInset(10);
+ assertEquals("Divider inset should be 10", 10, layout.getDividerInset());
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
-
- @Test
- public void testDividerInsets() {
- SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- }
- assertListTemplateInflated(layout);
-
- layout.setDividerInsets(10, 15);
- assertEquals("Divider inset start should be 10", 10, layout.getDividerInsetStart());
- assertEquals("Divider inset end should be 15", 15, layout.getDividerInsetEnd());
-
- final Drawable divider = layout.getDivider();
- assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
- }
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
- private void assertListTemplateInflated(SetupWizardLayout layout) {
- View decorView = layout.findViewById(R.id.suw_layout_decor);
- View navbar = layout.findViewById(R.id.suw_layout_navigation_bar);
- View title = layout.findViewById(R.id.suw_layout_title);
- View list = layout.findViewById(android.R.id.list);
- assertNotNull("@id/suw_layout_decor_view should not be null", decorView);
- assertTrue("@id/suw_layout_navigation_bar should be an instance of NavigationBar",
- navbar instanceof NavigationBar);
- assertNotNull("@id/suw_layout_title should not be null", title);
- assertTrue("@android:id/list should be an instance of ListView", list instanceof ListView);
+ @Test
+ public void testDividerInsets() {
+ SetupWizardListLayout layout = new SetupWizardListLayout(mContext);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
+ assertListTemplateInflated(layout);
+
+ layout.setDividerInsets(10, 15);
+ assertEquals("Divider inset start should be 10", 10, layout.getDividerInsetStart());
+ assertEquals("Divider inset end should be 15", 15, layout.getDividerInsetEnd());
+
+ final Drawable divider = layout.getDivider();
+ assertTrue("Divider should be instance of InsetDrawable", divider instanceof InsetDrawable);
+ }
+
+ private void assertListTemplateInflated(SetupWizardLayout layout) {
+ View decorView = layout.findViewById(R.id.suw_layout_decor);
+ View navbar = layout.findViewById(R.id.suw_layout_navigation_bar);
+ View title = layout.findViewById(R.id.suw_layout_title);
+ View list = layout.findViewById(android.R.id.list);
+ assertNotNull("@id/suw_layout_decor_view should not be null", decorView);
+ assertTrue(
+ "@id/suw_layout_navigation_bar should be an instance of NavigationBar",
+ navbar instanceof NavigationBar);
+ assertNotNull("@id/suw_layout_title should not be null", title);
+ assertTrue("@android:id/list should be an instance of ListView", list instanceof ListView);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/SimpleInflaterTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/SimpleInflaterTest.java
index f4738ca..da39a7b 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/SimpleInflaterTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/SimpleInflaterTest.java
@@ -20,15 +20,12 @@ import static org.junit.Assert.assertEquals;
import android.content.Context;
import android.content.res.Resources;
+import androidx.annotation.NonNull;
+import android.util.AttributeSet;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.util.AttributeSet;
-
-import androidx.annotation.NonNull;
-
import com.android.setupwizardlib.items.SimpleInflater;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,30 +33,30 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class SimpleInflaterTest {
- @Test
- public void testInflateXml() {
- final Context context = InstrumentationRegistry.getContext();
- TestInflater inflater = new TestInflater(context.getResources());
- final StringBuilder result = inflater.inflate(R.xml.simple_inflater_test);
+ @Test
+ public void testInflateXml() {
+ final Context context = InstrumentationRegistry.getContext();
+ TestInflater inflater = new TestInflater(context.getResources());
+ final StringBuilder result = inflater.inflate(R.xml.simple_inflater_test);
- assertEquals("Parent[null] > Child[foobar]", result.toString());
- }
+ assertEquals("Parent[null] > Child[foobar]", result.toString());
+ }
- private static class TestInflater extends SimpleInflater<StringBuilder> {
+ private static class TestInflater extends SimpleInflater<StringBuilder> {
- protected TestInflater(@NonNull Resources resources) {
- super(resources);
- }
+ protected TestInflater(@NonNull Resources resources) {
+ super(resources);
+ }
- @Override
- protected StringBuilder onCreateItem(String tagName, AttributeSet attrs) {
- final String attribute = attrs.getAttributeValue(null, "myattribute");
- return new StringBuilder(tagName).append("[").append(attribute).append("]");
- }
+ @Override
+ protected StringBuilder onCreateItem(String tagName, AttributeSet attrs) {
+ final String attribute = attrs.getAttributeValue(null, "myattribute");
+ return new StringBuilder(tagName).append("[").append(attribute).append("]");
+ }
- @Override
- protected void onAddChildItem(StringBuilder parent, StringBuilder child) {
- parent.append(" > ").append(child);
- }
+ @Override
+ protected void onAddChildItem(StringBuilder parent, StringBuilder child) {
+ parent.append(" > ").append(child);
}
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/SpanHelperTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/SpanHelperTest.java
index 903cf5e..920d7ab 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/SpanHelperTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/SpanHelperTest.java
@@ -19,13 +19,11 @@ package com.android.setupwizardlib.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.Annotation;
import android.text.SpannableStringBuilder;
-
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.setupwizardlib.span.SpanHelper;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,17 +31,17 @@ import org.junit.runner.RunWith;
@SmallTest
public class SpanHelperTest {
- @Test
- public void testReplaceSpan() {
- SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
- Annotation oldSpan = new Annotation("key", "value");
- Annotation newSpan = new Annotation("newkey", "newvalue");
- ssb.setSpan(oldSpan, 2, 5, 0 /* flags */);
+ @Test
+ public void testReplaceSpan() {
+ SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
+ Annotation oldSpan = new Annotation("key", "value");
+ Annotation newSpan = new Annotation("newkey", "newvalue");
+ ssb.setSpan(oldSpan, 2, 5, 0 /* flags */);
- SpanHelper.replaceSpan(ssb, oldSpan, newSpan);
+ SpanHelper.replaceSpan(ssb, oldSpan, newSpan);
- final Object[] spans = ssb.getSpans(0, ssb.length(), Object.class);
- assertEquals("There should be one span in the builder", 1, spans.length);
- assertSame("The span should be newSpan", newSpan, spans[0]);
- }
+ final Object[] spans = ssb.getSpans(0, ssb.length(), Object.class);
+ assertEquals("There should be one span in the builder", 1, spans.length);
+ assertSame("The span should be newSpan", newSpan, spans[0]);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/StatusBarBackgroundLayoutTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/StatusBarBackgroundLayoutTest.java
index 006e5c4..e0fd49b 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/StatusBarBackgroundLayoutTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/StatusBarBackgroundLayoutTest.java
@@ -24,9 +24,7 @@ import android.graphics.drawable.ShapeDrawable;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-
import com.android.setupwizardlib.view.StatusBarBackgroundLayout;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,46 +32,48 @@ import org.junit.runner.RunWith;
@SmallTest
public class StatusBarBackgroundLayoutTest {
- @Test
- public void testSetStatusBarBackground() {
- final StatusBarBackgroundLayout layout = new StatusBarBackgroundLayout(
- InstrumentationRegistry.getContext());
- final ShapeDrawable drawable = new ShapeDrawable();
- layout.setStatusBarBackground(drawable);
- assertSame("Status bar background drawable should be same as set",
- drawable, layout.getStatusBarBackground());
- }
+ @Test
+ public void testSetStatusBarBackground() {
+ final StatusBarBackgroundLayout layout =
+ new StatusBarBackgroundLayout(InstrumentationRegistry.getContext());
+ final ShapeDrawable drawable = new ShapeDrawable();
+ layout.setStatusBarBackground(drawable);
+ assertSame(
+ "Status bar background drawable should be same as set",
+ drawable,
+ layout.getStatusBarBackground());
+ }
- @Test
- public void testAttachedToWindow() {
- // Attaching to window should request apply window inset
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
- final TestStatusBarBackgroundLayout layout =
- new TestStatusBarBackgroundLayout(InstrumentationRegistry.getContext());
- layout.mRequestApplyInsets = false;
- layout.onAttachedToWindow();
+ @Test
+ public void testAttachedToWindow() {
+ // Attaching to window should request apply window inset
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+ final TestStatusBarBackgroundLayout layout =
+ new TestStatusBarBackgroundLayout(InstrumentationRegistry.getContext());
+ layout.mRequestApplyInsets = false;
+ layout.onAttachedToWindow();
- assertTrue("Attaching to window should apply window inset", layout.mRequestApplyInsets);
- }
+ assertTrue("Attaching to window should apply window inset", layout.mRequestApplyInsets);
}
+ }
- private static class TestStatusBarBackgroundLayout extends StatusBarBackgroundLayout {
+ private static class TestStatusBarBackgroundLayout extends StatusBarBackgroundLayout {
- boolean mRequestApplyInsets = false;
+ boolean mRequestApplyInsets = false;
- TestStatusBarBackgroundLayout(Context context) {
- super(context);
- }
+ TestStatusBarBackgroundLayout(Context context) {
+ super(context);
+ }
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- }
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ }
- @Override
- public void requestApplyInsets() {
- super.requestApplyInsets();
- mRequestApplyInsets = true;
- }
+ @Override
+ public void requestApplyInsets() {
+ super.requestApplyInsets();
+ mRequestApplyInsets = true;
}
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/SystemBarHelperTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/SystemBarHelperTest.java
index 98c28f6..1b534e1 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/SystemBarHelperTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/SystemBarHelperTest.java
@@ -17,7 +17,6 @@
package com.android.setupwizardlib.test;
import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import android.annotation.SuppressLint;
@@ -28,19 +27,17 @@ import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
import android.support.test.InstrumentationRegistry;
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.ContextThemeWrapper;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-
import com.android.setupwizardlib.test.util.MockWindow;
import com.android.setupwizardlib.util.SystemBarHelper;
-
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,241 +46,240 @@ import org.junit.runner.RunWith;
@SmallTest
public class SystemBarHelperTest {
- @Rule
- public UiThreadTestRule mUiThreadTestRule = new UiThreadTestRule();
-
- private static final int STATUS_BAR_DISABLE_BACK = 0x00400000;
-
- @SuppressLint("InlinedApi")
- private static final int DEFAULT_IMMERSIVE_FLAGS =
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-
- @SuppressLint("InlinedApi")
- private static final int DIALOG_IMMERSIVE_FLAGS =
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-
- @UiThreadTest
- @Test
- public void testAddVisibilityFlagView() {
- final View view = createViewWithSystemUiVisibility(0x456);
- SystemBarHelper.addVisibilityFlag(view, 0x1400);
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- // Check that result is 0x1456, because 0x1400 | 0x456 = 0x1456.
- assertEquals("View visibility should be 0x1456", 0x1456, view.getSystemUiVisibility());
- }
+ @Rule public UiThreadTestRule mUiThreadTestRule = new UiThreadTestRule();
+
+ private static final int STATUS_BAR_DISABLE_BACK = 0x00400000;
+
+ @SuppressLint("InlinedApi")
+ private static final int DEFAULT_IMMERSIVE_FLAGS =
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+
+ @SuppressLint("InlinedApi")
+ private static final int DIALOG_IMMERSIVE_FLAGS =
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+
+ @UiThreadTest
+ @Test
+ public void testAddVisibilityFlagView() {
+ final View view = createViewWithSystemUiVisibility(0x456);
+ SystemBarHelper.addVisibilityFlag(view, 0x1400);
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ // Check that result is 0x1456, because 0x1400 | 0x456 = 0x1456.
+ assertEquals("View visibility should be 0x1456", 0x1456, view.getSystemUiVisibility());
}
-
- @UiThreadTest
- @Test
- public void testRemoveVisibilityFlagView() {
- final View view = createViewWithSystemUiVisibility(0x456);
- SystemBarHelper.removeVisibilityFlag(view, 0x1400);
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- // Check that result is 0x56, because 0x456 & ~0x1400 = 0x56.
- assertEquals("View visibility should be 0x56", 0x56, view.getSystemUiVisibility());
- }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testRemoveVisibilityFlagView() {
+ final View view = createViewWithSystemUiVisibility(0x456);
+ SystemBarHelper.removeVisibilityFlag(view, 0x1400);
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ // Check that result is 0x56, because 0x456 & ~0x1400 = 0x56.
+ assertEquals("View visibility should be 0x56", 0x56, view.getSystemUiVisibility());
}
-
- @UiThreadTest
- @Test
- public void testAddVisibilityFlagWindow() {
- final Window window = createWindowWithSystemUiVisibility(0x456);
- SystemBarHelper.addVisibilityFlag(window, 0x1400);
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- // Check that result is 0x1456 = 0x1400 | 0x456.
- assertEquals("View visibility should be 0x1456", 0x1456,
- window.getAttributes().systemUiVisibility);
- }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testAddVisibilityFlagWindow() {
+ final Window window = createWindowWithSystemUiVisibility(0x456);
+ SystemBarHelper.addVisibilityFlag(window, 0x1400);
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ // Check that result is 0x1456 = 0x1400 | 0x456.
+ assertEquals(
+ "View visibility should be 0x1456", 0x1456, window.getAttributes().systemUiVisibility);
}
-
- @UiThreadTest
- @Test
- public void testRemoveVisibilityFlagWindow() {
- final Window window = createWindowWithSystemUiVisibility(0x456);
- SystemBarHelper.removeVisibilityFlag(window, 0x1400);
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- // Check that result is 0x56 = 0x456 & ~0x1400.
- assertEquals("View visibility should be 0x56", 0x56,
- window.getAttributes().systemUiVisibility);
- }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testRemoveVisibilityFlagWindow() {
+ final Window window = createWindowWithSystemUiVisibility(0x456);
+ SystemBarHelper.removeVisibilityFlag(window, 0x1400);
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ // Check that result is 0x56 = 0x456 & ~0x1400.
+ assertEquals(
+ "View visibility should be 0x56", 0x56, window.getAttributes().systemUiVisibility);
}
-
- @UiThreadTest
- @Test
- public void testHideSystemBarsWindow() {
- final Window window = createWindowWithSystemUiVisibility(0x456);
- SystemBarHelper.hideSystemBars(window);
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- assertEquals("DEFAULT_IMMERSIVE_FLAGS should be added to window's systemUiVisibility",
- DEFAULT_IMMERSIVE_FLAGS | 0x456,
- window.getAttributes().systemUiVisibility);
- assertEquals(
- "DEFAULT_IMMERSIVE_FLAGS should be added to decorView's systemUiVisibility",
- DEFAULT_IMMERSIVE_FLAGS | 0x456,
- window.getDecorView().getSystemUiVisibility());
- assertEquals("Navigation bar should be transparent", window.getNavigationBarColor(), 0);
- assertEquals("Status bar should be transparent", window.getStatusBarColor(), 0);
- }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testHideSystemBarsWindow() {
+ final Window window = createWindowWithSystemUiVisibility(0x456);
+ SystemBarHelper.hideSystemBars(window);
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ assertEquals(
+ "DEFAULT_IMMERSIVE_FLAGS should be added to window's systemUiVisibility",
+ DEFAULT_IMMERSIVE_FLAGS | 0x456,
+ window.getAttributes().systemUiVisibility);
+ assertEquals(
+ "DEFAULT_IMMERSIVE_FLAGS should be added to decorView's systemUiVisibility",
+ DEFAULT_IMMERSIVE_FLAGS | 0x456,
+ window.getDecorView().getSystemUiVisibility());
+ assertEquals("Navigation bar should be transparent", window.getNavigationBarColor(), 0);
+ assertEquals("Status bar should be transparent", window.getStatusBarColor(), 0);
}
-
- @UiThreadTest
- @Test
- public void testShowSystemBarsWindow() {
- final Window window = createWindowWithSystemUiVisibility(0x456);
- Context context = new ContextThemeWrapper(
- InstrumentationRegistry.getContext(), android.R.style.Theme);
- SystemBarHelper.showSystemBars(window, context);
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- assertEquals(
- "DEFAULT_IMMERSIVE_FLAGS should be removed from window's systemUiVisibility",
- 0x456 & ~DEFAULT_IMMERSIVE_FLAGS,
- window.getAttributes().systemUiVisibility);
- assertEquals(
- "DEFAULT_IMMERSIVE_FLAGS should be removed from decorView's systemUiVisibility",
- 0x456 & ~DEFAULT_IMMERSIVE_FLAGS,
- window.getDecorView().getSystemUiVisibility());
- assertEquals("Navigation bar should not be transparent",
- window.getNavigationBarColor(), 0xff000000);
- assertEquals("Status bar should not be transparent",
- window.getStatusBarColor(), 0xff000000);
- }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testShowSystemBarsWindow() {
+ final Window window = createWindowWithSystemUiVisibility(0x456);
+ Context context =
+ new ContextThemeWrapper(InstrumentationRegistry.getContext(), android.R.style.Theme);
+ SystemBarHelper.showSystemBars(window, context);
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ assertEquals(
+ "DEFAULT_IMMERSIVE_FLAGS should be removed from window's systemUiVisibility",
+ 0x456 & ~DEFAULT_IMMERSIVE_FLAGS,
+ window.getAttributes().systemUiVisibility);
+ assertEquals(
+ "DEFAULT_IMMERSIVE_FLAGS should be removed from decorView's systemUiVisibility",
+ 0x456 & ~DEFAULT_IMMERSIVE_FLAGS,
+ window.getDecorView().getSystemUiVisibility());
+ assertEquals(
+ "Navigation bar should not be transparent", window.getNavigationBarColor(), 0xff000000);
+ assertEquals("Status bar should not be transparent", window.getStatusBarColor(), 0xff000000);
}
-
- @UiThreadTest
- @Test
- public void testHideSystemBarsNoInfiniteLoop() throws InterruptedException {
- final TestWindow window = new TestWindow(InstrumentationRegistry.getContext(), null);
- final HandlerThread thread = new HandlerThread("SystemBarHelperTest");
- thread.start();
- final Handler handler = new Handler(thread.getLooper());
- handler.post(new Runnable() {
- @Override
- public void run() {
- SystemBarHelper.hideSystemBars(window);
- }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testHideSystemBarsNoInfiniteLoop() throws InterruptedException {
+ final TestWindow window = new TestWindow(InstrumentationRegistry.getContext(), null);
+ final HandlerThread thread = new HandlerThread("SystemBarHelperTest");
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+ handler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ SystemBarHelper.hideSystemBars(window);
+ }
});
- SystemClock.sleep(500); // Wait for the looper to drain all the messages
- thread.quit();
- // Initial peek + 3 retries = 4 tries total
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- assertEquals("Peek decor view should give up after 4 tries", 4,
- window.peekDecorViewCount);
- }
+ SystemClock.sleep(500); // Wait for the looper to drain all the messages
+ thread.quit();
+ // Initial peek + 3 retries = 4 tries total
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ assertEquals("Peek decor view should give up after 4 tries", 4, window.peekDecorViewCount);
}
-
- @UiThreadTest
- @Test
- public void testHideSystemBarsDialog() {
- final Dialog dialog = new Dialog(InstrumentationRegistry.getContext());
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- final WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
- attrs.systemUiVisibility = 0x456;
- dialog.getWindow().setAttributes(attrs);
- }
-
- SystemBarHelper.hideSystemBars(dialog);
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- assertEquals("DIALOG_IMMERSIVE_FLAGS should be added to window's systemUiVisibility",
- DIALOG_IMMERSIVE_FLAGS | 0x456,
- dialog.getWindow().getAttributes().systemUiVisibility);
- }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testHideSystemBarsDialog() {
+ final Dialog dialog = new Dialog(InstrumentationRegistry.getContext());
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ final WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
+ attrs.systemUiVisibility = 0x456;
+ dialog.getWindow().setAttributes(attrs);
}
- @UiThreadTest
- @Test
- public void testSetBackButtonVisibleTrue() {
- final Window window = createWindowWithSystemUiVisibility(STATUS_BAR_DISABLE_BACK | 0x456);
- SystemBarHelper.setBackButtonVisible(window, true);
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- assertThat(window.getAttributes().systemUiVisibility)
- .named("window sysUiVisibility")
- .isEqualTo(0x456);
- assertThat(window.getDecorView().getSystemUiVisibility())
- .named("decor view sysUiVisibility")
- .isEqualTo(0x456);
- }
+ SystemBarHelper.hideSystemBars(dialog);
+ if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ assertEquals(
+ "DIALOG_IMMERSIVE_FLAGS should be added to window's systemUiVisibility",
+ DIALOG_IMMERSIVE_FLAGS | 0x456,
+ dialog.getWindow().getAttributes().systemUiVisibility);
}
-
- @UiThreadTest
- @Test
- public void testSetBackButtonVisibleFalse() {
- final Window window = createWindowWithSystemUiVisibility(0x456);
- SystemBarHelper.setBackButtonVisible(window, false);
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- assertThat(window.getAttributes().systemUiVisibility)
- .named("window sysUiVisibility")
- .isEqualTo(0x456 | STATUS_BAR_DISABLE_BACK);
- assertThat(window.getDecorView().getSystemUiVisibility())
- .named("decor view sysUiVisibility")
- .isEqualTo(0x456 | STATUS_BAR_DISABLE_BACK);
- }
+ }
+
+ @UiThreadTest
+ @Test
+ public void testSetBackButtonVisibleTrue() {
+ final Window window = createWindowWithSystemUiVisibility(STATUS_BAR_DISABLE_BACK | 0x456);
+ SystemBarHelper.setBackButtonVisible(window, true);
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ assertThat(window.getAttributes().systemUiVisibility)
+ .named("window sysUiVisibility")
+ .isEqualTo(0x456);
+ assertThat(window.getDecorView().getSystemUiVisibility())
+ .named("decor view sysUiVisibility")
+ .isEqualTo(0x456);
}
-
- private View createViewWithSystemUiVisibility(int vis) {
- final View view = new View(InstrumentationRegistry.getContext());
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- view.setSystemUiVisibility(vis);
- }
- return view;
+ }
+
+ @UiThreadTest
+ @Test
+ public void testSetBackButtonVisibleFalse() {
+ final Window window = createWindowWithSystemUiVisibility(0x456);
+ SystemBarHelper.setBackButtonVisible(window, false);
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ assertThat(window.getAttributes().systemUiVisibility)
+ .named("window sysUiVisibility")
+ .isEqualTo(0x456 | STATUS_BAR_DISABLE_BACK);
+ assertThat(window.getDecorView().getSystemUiVisibility())
+ .named("decor view sysUiVisibility")
+ .isEqualTo(0x456 | STATUS_BAR_DISABLE_BACK);
}
+ }
- private Window createWindowWithSystemUiVisibility(int vis) {
- final Window window = new TestWindow(InstrumentationRegistry.getContext(),
- createViewWithSystemUiVisibility(vis));
- if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
- WindowManager.LayoutParams attrs = window.getAttributes();
- attrs.systemUiVisibility = vis;
- window.setAttributes(attrs);
- }
- return window;
+ private View createViewWithSystemUiVisibility(int vis) {
+ final View view = new View(InstrumentationRegistry.getContext());
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ view.setSystemUiVisibility(vis);
+ }
+ return view;
+ }
+
+ private Window createWindowWithSystemUiVisibility(int vis) {
+ final Window window =
+ new TestWindow(InstrumentationRegistry.getContext(), createViewWithSystemUiVisibility(vis));
+ if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
+ WindowManager.LayoutParams attrs = window.getAttributes();
+ attrs.systemUiVisibility = vis;
+ window.setAttributes(attrs);
}
+ return window;
+ }
- private static class TestWindow extends MockWindow {
+ private static class TestWindow extends MockWindow {
- private View mDecorView;
- public int peekDecorViewCount = 0;
+ private View mDecorView;
+ public int peekDecorViewCount = 0;
- private int mNavigationBarColor = -1;
- private int mStatusBarColor = -1;
+ private int mNavigationBarColor = -1;
+ private int mStatusBarColor = -1;
- TestWindow(Context context, View decorView) {
- super(context);
- mDecorView = decorView;
- }
+ TestWindow(Context context, View decorView) {
+ super(context);
+ mDecorView = decorView;
+ }
- @Override
- public View getDecorView() {
- return mDecorView;
- }
+ @Override
+ public View getDecorView() {
+ return mDecorView;
+ }
- @Override
- public View peekDecorView() {
- peekDecorViewCount++;
- return mDecorView;
- }
+ @Override
+ public View peekDecorView() {
+ peekDecorViewCount++;
+ return mDecorView;
+ }
- @Override
- public void setNavigationBarColor(int i) {
- mNavigationBarColor = i;
- }
+ @Override
+ public void setNavigationBarColor(int i) {
+ mNavigationBarColor = i;
+ }
- @Override
- public int getNavigationBarColor() {
- return mNavigationBarColor;
- }
+ @Override
+ public int getNavigationBarColor() {
+ return mNavigationBarColor;
+ }
- @Override
- public void setStatusBarColor(int i) {
- mStatusBarColor = i;
- }
+ @Override
+ public void setStatusBarColor(int i) {
+ mStatusBarColor = i;
+ }
- @Override
- public int getStatusBarColor() {
- return mStatusBarColor;
- }
+ @Override
+ public int getStatusBarColor() {
+ return mStatusBarColor;
}
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestHelper.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestHelper.java
index 6910513..918d63a 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestHelper.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/util/DrawingTestHelper.java
@@ -24,69 +24,69 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.support.test.InstrumentationRegistry;
+import androidx.annotation.StyleRes;
import android.view.View;
import android.view.View.MeasureSpec;
-
-import androidx.annotation.StyleRes;
+import android.support.test.InstrumentationRegistry;
public class DrawingTestHelper {
- /**
- * Creates an activity of which to inflate views and drawables for drawing tests. This method
- * will return an instance of AppCompatActivity which allows testing of drawing behavior
- * injected by support libraries (like drawable tinting) as well.
- */
- public static Activity createCanvasActivity(@StyleRes int theme)
- throws IllegalAccessException, InstantiationException {
- final Context context = InstrumentationRegistry.getTargetContext();
- final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ /**
+ * Creates an activity of which to inflate views and drawables for drawing tests. This method will
+ * return an instance of AppCompatActivity which allows testing of drawing behavior injected by
+ * support libraries (like drawable tinting) as well.
+ */
+ public static Activity createCanvasActivity(@StyleRes int theme)
+ throws IllegalAccessException, InstantiationException {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- final Intent intent = new Intent(context, DrawingTestActivity.class);
- final Activity activity = instrumentation.newActivity(
- DrawingTestActivity.class,
- context,
- null, /* token */
- new Application(),
- intent,
- new ActivityInfo(),
- "", /* title */
- null, /* parent */
- null, /* id */
- null /* lastNonConfigurationInstance */);
- instrumentation.callActivityOnCreate(activity, null);
- activity.setTheme(theme);
- return activity;
- }
+ final Intent intent = new Intent(context, DrawingTestActivity.class);
+ final Activity activity =
+ instrumentation.newActivity(
+ DrawingTestActivity.class,
+ context,
+ null, /* token */
+ new Application(),
+ intent,
+ new ActivityInfo(),
+ "", /* title */
+ null, /* parent */
+ null, /* id */
+ null /* lastNonConfigurationInstance */);
+ instrumentation.callActivityOnCreate(activity, null);
+ activity.setTheme(theme);
+ return activity;
+ }
- private final int mWidth;
- private final int mHeight;
- private final Canvas mCanvas;
- private final Bitmap mBitmap;
+ private final int mWidth;
+ private final int mHeight;
+ private final Canvas mCanvas;
+ private final Bitmap mBitmap;
- public DrawingTestHelper(int width, int height) {
- mWidth = width;
- mHeight = height;
+ public DrawingTestHelper(int width, int height) {
+ mWidth = width;
+ mHeight = height;
- mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- mCanvas = new Canvas(mBitmap);
- }
+ mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ mCanvas = new Canvas(mBitmap);
+ }
- public void drawView(View view) {
- view.measure(
- MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
- view.layout(0, 0, mWidth, mHeight);
- view.draw(mCanvas);
- }
+ public void drawView(View view) {
+ view.measure(
+ MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
+ view.layout(0, 0, mWidth, mHeight);
+ view.draw(mCanvas);
+ }
- public int[] getPixels() {
- int[] out = new int[mWidth * mHeight];
- mBitmap.getPixels(out, 0, mWidth, 0, 0, mWidth, mHeight);
- return out;
- }
+ public int[] getPixels() {
+ int[] out = new int[mWidth * mHeight];
+ mBitmap.getPixels(out, 0, mWidth, 0, 0, mWidth, mHeight);
+ return out;
+ }
- public int getPixel(int x, int y) {
- return mBitmap.getPixel(x, y);
- }
+ public int getPixel(int x, int y) {
+ return mBitmap.getPixel(x, y);
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/test/util/MockWindow.java b/library/test/instrumentation/src/com/android/setupwizardlib/test/util/MockWindow.java
index 7af20eb..1e096eb 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/test/util/MockWindow.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/test/util/MockWindow.java
@@ -21,6 +21,7 @@ import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import androidx.annotation.NonNull;
import android.view.InputQueue;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -30,252 +31,250 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import androidx.annotation.NonNull;
-
public class MockWindow extends Window {
- public MockWindow(Context context) {
- super(context);
- }
-
- @Override
- public void takeSurface(SurfaceHolder.Callback2 callback2) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void takeInputQueue(InputQueue.Callback callback) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean isFloating() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setContentView(int i) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setContentView(View view) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setContentView(View view, ViewGroup.LayoutParams layoutParams) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void addContentView(View view, ViewGroup.LayoutParams layoutParams) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public View getCurrentFocus() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @NonNull
- @Override
- public LayoutInflater getLayoutInflater() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setTitle(CharSequence charSequence) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setTitleColor(int i) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void openPanel(int i, KeyEvent keyEvent) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void closePanel(int i) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void togglePanel(int i, KeyEvent keyEvent) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void invalidatePanelMenu(int i) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean performPanelShortcut(int i, int i1, KeyEvent keyEvent, int i2) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean performPanelIdentifierAction(int i, int i1, int i2) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void closeAllPanels() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean performContextMenuIdentifierAction(int i, int i1) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void onConfigurationChanged(Configuration configuration) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setBackgroundDrawable(Drawable drawable) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setFeatureDrawableResource(int i, int i1) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setFeatureDrawableUri(int i, Uri uri) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setFeatureDrawable(int i, Drawable drawable) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setFeatureDrawableAlpha(int i, int i1) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setFeatureInt(int i, int i1) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void takeKeyEvents(boolean b) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean superDispatchKeyEvent(KeyEvent keyEvent) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean superDispatchKeyShortcutEvent(KeyEvent keyEvent) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean superDispatchTouchEvent(MotionEvent motionEvent) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean superDispatchTrackballEvent(MotionEvent motionEvent) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean superDispatchGenericMotionEvent(MotionEvent motionEvent) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public View getDecorView() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public View peekDecorView() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public Bundle saveHierarchyState() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void restoreHierarchyState(Bundle bundle) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- protected void onActive() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setChildDrawable(int i, Drawable drawable) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setChildInt(int i, int i1) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public boolean isShortcutKey(int i, KeyEvent keyEvent) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setVolumeControlStream(int i) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public int getVolumeControlStream() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public int getStatusBarColor() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setStatusBarColor(int i) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public int getNavigationBarColor() {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setNavigationBarColor(int i) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setDecorCaptionShade(int i) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
-
- @Override
- public void setResizingCaptionDrawable(Drawable drawable) {
- throw new UnsupportedOperationException("Unexpected method call on mock");
- }
+ public MockWindow(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void takeSurface(SurfaceHolder.Callback2 callback2) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void takeInputQueue(InputQueue.Callback callback) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean isFloating() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setContentView(int i) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setContentView(View view) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setContentView(View view, ViewGroup.LayoutParams layoutParams) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void addContentView(View view, ViewGroup.LayoutParams layoutParams) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public View getCurrentFocus() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @NonNull
+ @Override
+ public LayoutInflater getLayoutInflater() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setTitle(CharSequence charSequence) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setTitleColor(int i) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void openPanel(int i, KeyEvent keyEvent) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void closePanel(int i) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void togglePanel(int i, KeyEvent keyEvent) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void invalidatePanelMenu(int i) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean performPanelShortcut(int i, int i1, KeyEvent keyEvent, int i2) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean performPanelIdentifierAction(int i, int i1, int i2) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void closeAllPanels() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean performContextMenuIdentifierAction(int i, int i1) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration configuration) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setBackgroundDrawable(Drawable drawable) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setFeatureDrawableResource(int i, int i1) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setFeatureDrawableUri(int i, Uri uri) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setFeatureDrawable(int i, Drawable drawable) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setFeatureDrawableAlpha(int i, int i1) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setFeatureInt(int i, int i1) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void takeKeyEvents(boolean b) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean superDispatchKeyEvent(KeyEvent keyEvent) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean superDispatchKeyShortcutEvent(KeyEvent keyEvent) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean superDispatchTouchEvent(MotionEvent motionEvent) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean superDispatchTrackballEvent(MotionEvent motionEvent) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean superDispatchGenericMotionEvent(MotionEvent motionEvent) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public View getDecorView() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public View peekDecorView() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public Bundle saveHierarchyState() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void restoreHierarchyState(Bundle bundle) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ protected void onActive() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setChildDrawable(int i, Drawable drawable) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setChildInt(int i, int i1) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public boolean isShortcutKey(int i, KeyEvent keyEvent) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setVolumeControlStream(int i) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public int getVolumeControlStream() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public int getStatusBarColor() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setStatusBarColor(int i) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public int getNavigationBarColor() {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setNavigationBarColor(int i) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setDecorCaptionShade(int i) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
+
+ @Override
+ public void setResizingCaptionDrawable(Drawable drawable) {
+ throw new UnsupportedOperationException("Unexpected method call on mock");
+ }
}
diff --git a/library/test/instrumentation/src/com/android/setupwizardlib/util/FallbackThemeWrapperTest.java b/library/test/instrumentation/src/com/android/setupwizardlib/util/FallbackThemeWrapperTest.java
index d492765..99d997b 100644
--- a/library/test/instrumentation/src/com/android/setupwizardlib/util/FallbackThemeWrapperTest.java
+++ b/library/test/instrumentation/src/com/android/setupwizardlib/util/FallbackThemeWrapperTest.java
@@ -20,13 +20,11 @@ import static org.junit.Assert.assertEquals;
import android.content.Context;
import android.content.res.TypedArray;
+import android.view.ContextThemeWrapper;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.ContextThemeWrapper;
-
import com.android.setupwizardlib.test.R;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,37 +33,35 @@ import org.junit.runner.RunWith;
@SmallTest
public class FallbackThemeWrapperTest {
- private FallbackThemeWrapper mThemedContext;
+ private FallbackThemeWrapper mThemedContext;
- @Before
- public void setUp() {
- Context baseContext = new ContextThemeWrapper(
- InstrumentationRegistry.getContext(),
- R.style.TestBaseTheme);
- mThemedContext = new FallbackThemeWrapper(baseContext, R.style.TestFallbackTheme);
- }
+ @Before
+ public void setUp() {
+ Context baseContext =
+ new ContextThemeWrapper(InstrumentationRegistry.getContext(), R.style.TestBaseTheme);
+ mThemedContext = new FallbackThemeWrapper(baseContext, R.style.TestFallbackTheme);
+ }
- @Test
- public void testThemeValueOnlyInBase() {
- final TypedArray a =
- mThemedContext.obtainStyledAttributes(new int[] {android.R.attr.background});
- assertEquals(0xffff0000, a.getColor(0, 0));
- a.recycle();
- }
+ @Test
+ public void testThemeValueOnlyInBase() {
+ final TypedArray a =
+ mThemedContext.obtainStyledAttributes(new int[] {android.R.attr.background});
+ assertEquals(0xffff0000, a.getColor(0, 0));
+ a.recycle();
+ }
- @Test
- public void testThemeValueOnlyInFallback() {
- final TypedArray a =
- mThemedContext.obtainStyledAttributes(new int[] {android.R.attr.foreground});
- assertEquals(0xff0000ff, a.getColor(0, 0));
- a.recycle();
- }
+ @Test
+ public void testThemeValueOnlyInFallback() {
+ final TypedArray a =
+ mThemedContext.obtainStyledAttributes(new int[] {android.R.attr.foreground});
+ assertEquals(0xff0000ff, a.getColor(0, 0));
+ a.recycle();
+ }
- @Test
- public void testThemeValueInBoth() {
- final TypedArray a =
- mThemedContext.obtainStyledAttributes(new int[] {android.R.attr.theme});
- assertEquals(R.style.TestBaseTheme, a.getResourceId(0, 0));
- a.recycle();
- }
+ @Test
+ public void testThemeValueInBoth() {
+ final TypedArray a = mThemedContext.obtainStyledAttributes(new int[] {android.R.attr.theme});
+ assertEquals(R.style.TestBaseTheme, a.getResourceId(0, 0));
+ a.recycle();
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java b/library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java
index 2a4a8c0..d77838f 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/GlifLayoutTest.java
@@ -16,14 +16,8 @@
package com.android.setupwizardlib;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.robolectric.RuntimeEnvironment.application;
import android.content.Context;
@@ -34,328 +28,337 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
+import androidx.annotation.IdRes;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
-
-import androidx.annotation.IdRes;
-
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
import com.android.setupwizardlib.template.ColoredHeaderMixin;
import com.android.setupwizardlib.template.HeaderMixin;
import com.android.setupwizardlib.template.IconMixin;
import com.android.setupwizardlib.template.ProgressBarMixin;
import com.android.setupwizardlib.view.StatusBarBackgroundLayout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
public class GlifLayoutTest {
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
- }
-
- @Test
- public void testDefaultTemplate() {
- GlifLayout layout = new GlifLayout(mContext);
- assertDefaultTemplateInflated(layout);
- }
-
- @Test
- public void testSetHeaderText() {
- GlifLayout layout = new GlifLayout(mContext);
- TextView title = (TextView) layout.findViewById(R.id.suw_layout_title);
- layout.setHeaderText("Abracadabra");
- assertEquals("Header text should be \"Abracadabra\"", "Abracadabra", title.getText());
- }
-
- @Test
- public void testAddView() {
- @IdRes int testViewId = 123456;
- GlifLayout layout = new GlifLayout(mContext);
- TextView tv = new TextView(mContext);
- tv.setId(testViewId);
- layout.addView(tv);
- assertDefaultTemplateInflated(layout);
- View view = layout.findViewById(testViewId);
- assertSame("The view added should be the same text view", tv, view);
- }
-
- @Test
- public void testGetScrollView() {
- GlifLayout layout = new GlifLayout(mContext);
- assertNotNull("Get scroll view should not be null with default template",
- layout.getScrollView());
- }
-
- @Test
- public void testSetPrimaryColor() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setProgressBarShown(true);
- layout.setPrimaryColor(ColorStateList.valueOf(Color.RED));
- assertEquals("Primary color should be red",
- ColorStateList.valueOf(Color.RED), layout.getPrimaryColor());
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- ProgressBar progressBar = (ProgressBar) layout.findViewById(R.id.suw_layout_progress);
- assertEquals("Progress bar should be tinted red",
- ColorStateList.valueOf(Color.RED), progressBar.getIndeterminateTintList());
- assertEquals("Determinate progress bar should also be tinted red",
- ColorStateList.valueOf(Color.RED), progressBar.getProgressBackgroundTintList());
- }
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void testSetPrimaryColorTablet() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setProgressBarShown(true);
- layout.setPrimaryColor(ColorStateList.valueOf(Color.RED));
- assertEquals("Primary color should be red",
- ColorStateList.valueOf(Color.RED), layout.getPrimaryColor());
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- ProgressBar progressBar = (ProgressBar) layout.findViewById(R.id.suw_layout_progress);
- assertEquals("Progress bar should be tinted red",
- ColorStateList.valueOf(Color.RED), progressBar.getIndeterminateTintList());
- assertEquals("Determinate progress bar should also be tinted red",
- ColorStateList.valueOf(Color.RED), progressBar.getProgressBackgroundTintList());
- }
-
- assertEquals(Color.RED, ((GlifPatternDrawable) getTabletBackground(layout)).getColor());
- }
-
- @Test
- public void testSetBackgroundBaseColor() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setPrimaryColor(ColorStateList.valueOf(Color.BLUE));
- layout.setBackgroundBaseColor(ColorStateList.valueOf(Color.RED));
-
- assertEquals(Color.RED, ((GlifPatternDrawable) getPhoneBackground(layout)).getColor());
- assertEquals(Color.RED, layout.getBackgroundBaseColor().getDefaultColor());
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void testSetBackgroundBaseColorTablet() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setPrimaryColor(ColorStateList.valueOf(Color.BLUE));
- layout.setBackgroundBaseColor(ColorStateList.valueOf(Color.RED));
-
- assertEquals(Color.RED, ((GlifPatternDrawable) getTabletBackground(layout)).getColor());
- assertEquals(Color.RED, layout.getBackgroundBaseColor().getDefaultColor());
- }
-
- @Test
- public void testSetBackgroundPatternedTrue() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setBackgroundPatterned(true);
-
- assertThat(getPhoneBackground(layout), instanceOf(GlifPatternDrawable.class));
- assertTrue("Background should be patterned", layout.isBackgroundPatterned());
- }
-
- @Test
- public void testSetBackgroundPatternedFalse() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setBackgroundPatterned(false);
-
- assertThat(getPhoneBackground(layout), instanceOf(ColorDrawable.class));
- assertFalse("Background should not be patterned", layout.isBackgroundPatterned());
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void testSetBackgroundPatternedTrueTablet() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setBackgroundPatterned(true);
-
- assertThat(getTabletBackground(layout), instanceOf(GlifPatternDrawable.class));
- assertTrue("Background should be patterned", layout.isBackgroundPatterned());
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void testSetBackgroundPatternedFalseTablet() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setBackgroundPatterned(false);
-
- assertThat(getTabletBackground(layout), instanceOf(ColorDrawable.class));
- assertFalse("Background should not be patterned", layout.isBackgroundPatterned());
- }
-
- @Test
- public void testNonGlifTheme() {
- mContext = new ContextThemeWrapper(application, android.R.style.Theme);
- new GlifLayout(mContext);
- // Inflating with a non-GLIF theme should not crash
- }
-
- @Test
- public void testPeekProgressBarNull() {
- GlifLayout layout = new GlifLayout(mContext);
- assertNull("PeekProgressBar should return null initially", layout.peekProgressBar());
- }
-
- @Test
- public void testPeekProgressBar() {
- GlifLayout layout = new GlifLayout(mContext);
- layout.setProgressBarShown(true);
- assertNotNull("Peek progress bar should return the bar after setProgressBarShown(true)",
- layout.peekProgressBar());
- }
-
- @Test
- public void testMixins() {
- GlifLayout layout = new GlifLayout(mContext);
- final HeaderMixin header = layout.getMixin(HeaderMixin.class);
- assertTrue("Header should be instance of ColoredHeaderMixin. "
- + "Found " + header.getClass() + " instead.", header instanceof ColoredHeaderMixin);
-
- assertNotNull("GlifLayout should have icon mixin", layout.getMixin(IconMixin.class));
- assertNotNull("GlifLayout should have progress bar mixin",
- layout.getMixin(ProgressBarMixin.class));
- }
-
- @Test
- public void testInflateFooter() {
- GlifLayout layout = new GlifLayout(mContext);
-
- final View view = layout.inflateFooter(android.R.layout.simple_list_item_1);
- assertEquals(android.R.id.text1, view.getId());
- assertNotNull(layout.findViewById(android.R.id.text1));
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void testInflateFooterTablet() {
- testInflateFooter();
- }
-
- @Test
- public void testInflateFooterBlankTemplate() {
- GlifLayout layout = new GlifLayout(mContext, R.layout.suw_glif_blank_template);
-
- final View view = layout.inflateFooter(android.R.layout.simple_list_item_1);
- assertEquals(android.R.id.text1, view.getId());
- assertNotNull(layout.findViewById(android.R.id.text1));
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void testInflateFooterBlankTemplateTablet() {
- testInflateFooterBlankTemplate();
- }
-
- @Test
- public void testFooterXml() {
- GlifLayout layout = new GlifLayout(
- mContext,
- Robolectric.buildAttributeSet()
- .addAttribute(R.attr.suwFooter, "@android:layout/simple_list_item_1")
- .build());
-
- assertNotNull(layout.findViewById(android.R.id.text1));
- }
-
- @Test
- public void inflateStickyHeader_shouldAddViewToLayout() {
- GlifLayout layout = new GlifLayout(mContext);
-
- final View view = layout.inflateStickyHeader(android.R.layout.simple_list_item_1);
- assertEquals(android.R.id.text1, view.getId());
- assertNotNull(layout.findViewById(android.R.id.text1));
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void inflateStickyHeader_whenOnTablets_shouldAddViewToLayout() {
- inflateStickyHeader_shouldAddViewToLayout();
- }
-
- @Test
- public void inflateStickyHeader_whenInXml_shouldAddViewToLayout() {
- GlifLayout layout = new GlifLayout(
- mContext,
- Robolectric.buildAttributeSet()
- .addAttribute(R.attr.suwStickyHeader, "@android:layout/simple_list_item_1")
- .build());
-
- assertNotNull(layout.findViewById(android.R.id.text1));
- }
-
- @Test
- public void inflateStickyHeader_whenOnBlankTemplate_shouldAddViewToLayout() {
- GlifLayout layout = new GlifLayout(mContext, R.layout.suw_glif_blank_template);
-
- final View view = layout.inflateStickyHeader(android.R.layout.simple_list_item_1);
- assertEquals(android.R.id.text1, view.getId());
- assertNotNull(layout.findViewById(android.R.id.text1));
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void inflateStickyHeader_whenOnBlankTemplateTablet_shouldAddViewToLayout() {
- inflateStickyHeader_whenOnBlankTemplate_shouldAddViewToLayout();
- }
-
- @Config(minSdk = Config.OLDEST_SDK, maxSdk = Config.NEWEST_SDK)
- @Test
- public void createFromXml_shouldSetLayoutFullscreen_whenLayoutFullscreenIsNotSet() {
- GlifLayout layout = new GlifLayout(
- mContext,
- Robolectric.buildAttributeSet()
- .build());
- if (VERSION.SDK_INT >= VERSION_CODES.M) {
- assertEquals(
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
- layout.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- }
- }
-
- @Test
- public void createFromXml_shouldNotSetLayoutFullscreen_whenLayoutFullscreenIsFalse() {
- GlifLayout layout = new GlifLayout(
- mContext,
- Robolectric.buildAttributeSet()
- .addAttribute(R.attr.suwLayoutFullscreen, "false")
- .build());
-
- assertEquals(
- 0,
- layout.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- }
-
- private Drawable getPhoneBackground(GlifLayout layout) {
- final StatusBarBackgroundLayout patternBg =
- (StatusBarBackgroundLayout) layout.findManagedViewById(R.id.suw_pattern_bg);
- return patternBg.getStatusBarBackground();
- }
-
- private Drawable getTabletBackground(GlifLayout layout) {
- final View patternBg = layout.findManagedViewById(R.id.suw_pattern_bg);
- return patternBg.getBackground();
- }
-
- private void assertDefaultTemplateInflated(GlifLayout layout) {
- View title = layout.findViewById(R.id.suw_layout_title);
- assertNotNull("@id/suw_layout_title should not be null", title);
-
- View icon = layout.findViewById(R.id.suw_layout_icon);
- assertNotNull("@id/suw_layout_icon should not be null", icon);
-
- View scrollView = layout.findViewById(R.id.suw_scroll_view);
- assertTrue("@id/suw_scroll_view should be a ScrollView", scrollView instanceof ScrollView);
- }
+ private Context context;
+
+ @Before
+ public void setUpContext() {
+ context = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
+ }
+
+ @Test
+ public void testDefaultTemplate() {
+ GlifLayout layout = new GlifLayout(context);
+ assertDefaultTemplateInflated(layout);
+ }
+
+ @Test
+ public void testSetHeaderText() {
+ GlifLayout layout = new GlifLayout(context);
+ TextView title = layout.findViewById(R.id.suw_layout_title);
+ layout.setHeaderText("Abracadabra");
+ assertWithMessage("Header text should be \"Abracadabra\"")
+ .that(title.getText().toString())
+ .isEqualTo("Abracadabra");
+ }
+
+ @Test
+ public void testAddView() {
+ @IdRes int testViewId = 123456;
+ GlifLayout layout = new GlifLayout(context);
+ TextView tv = new TextView(context);
+ tv.setId(testViewId);
+ layout.addView(tv);
+ assertDefaultTemplateInflated(layout);
+ View view = layout.findViewById(testViewId);
+ assertThat(view).named("Text view added").isSameAs(tv);
+ }
+
+ @Test
+ public void testGetScrollView() {
+ GlifLayout layout = new GlifLayout(context);
+ assertWithMessage("Get scroll view should not be null with default template")
+ .that(layout.getScrollView())
+ .isNotNull();
+ }
+
+ @Test
+ public void testSetPrimaryColor() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setProgressBarShown(true);
+ layout.setPrimaryColor(ColorStateList.valueOf(Color.RED));
+ assertWithMessage("Primary color should be red")
+ .that(layout.getPrimaryColor())
+ .isEqualTo(ColorStateList.valueOf(Color.RED));
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ ProgressBar progressBar = layout.findViewById(R.id.suw_layout_progress);
+ assertThat(progressBar.getIndeterminateTintList())
+ .named("indeterminate progress bar tint")
+ .isEqualTo(ColorStateList.valueOf(Color.RED));
+ assertThat(progressBar.getProgressBackgroundTintList())
+ .named("determinate progress bar tint")
+ .isEqualTo(ColorStateList.valueOf(Color.RED));
+ }
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void testSetPrimaryColorTablet() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setProgressBarShown(true);
+ layout.setPrimaryColor(ColorStateList.valueOf(Color.RED));
+ assertWithMessage("Primary color should be red")
+ .that(layout.getPrimaryColor())
+ .isEqualTo(ColorStateList.valueOf(Color.RED));
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ ProgressBar progressBar = layout.findViewById(R.id.suw_layout_progress);
+ assertWithMessage("Progress bar should be tinted red")
+ .that(progressBar.getIndeterminateTintList())
+ .isEqualTo(ColorStateList.valueOf(Color.RED));
+ assertWithMessage("Determinate progress bar should also be tinted red")
+ .that(progressBar.getProgressBackgroundTintList())
+ .isEqualTo(ColorStateList.valueOf(Color.RED));
+ }
+
+ assertThat(((GlifPatternDrawable) getTabletBackground(layout)).getColor()).isEqualTo(Color.RED);
+ }
+
+ @Test
+ public void testSetBackgroundBaseColor() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setPrimaryColor(ColorStateList.valueOf(Color.BLUE));
+ layout.setBackgroundBaseColor(ColorStateList.valueOf(Color.RED));
+
+ assertThat(((GlifPatternDrawable) getPhoneBackground(layout)).getColor()).isEqualTo(Color.RED);
+ assertThat(layout.getBackgroundBaseColor().getDefaultColor()).isEqualTo(Color.RED);
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void testSetBackgroundBaseColorTablet() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setPrimaryColor(ColorStateList.valueOf(Color.BLUE));
+ layout.setBackgroundBaseColor(ColorStateList.valueOf(Color.RED));
+
+ assertThat(((GlifPatternDrawable) getTabletBackground(layout)).getColor()).isEqualTo(Color.RED);
+ assertThat(layout.getBackgroundBaseColor().getDefaultColor()).isEqualTo(Color.RED);
+ }
+
+ @Test
+ public void testSetBackgroundPatternedTrue() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setBackgroundPatterned(true);
+
+ assertThat(getPhoneBackground(layout)).isInstanceOf(GlifPatternDrawable.class);
+ assertThat(layout.isBackgroundPatterned()).named("background is patterned").isTrue();
+ }
+
+ @Test
+ public void testSetBackgroundPatternedFalse() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setBackgroundPatterned(false);
+
+ assertThat(getPhoneBackground(layout)).isInstanceOf(ColorDrawable.class);
+ assertThat(layout.isBackgroundPatterned()).named("background is patterned").isFalse();
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void testSetBackgroundPatternedTrueTablet() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setBackgroundPatterned(true);
+
+ assertThat(getTabletBackground(layout)).isInstanceOf(GlifPatternDrawable.class);
+ assertThat(layout.isBackgroundPatterned()).named("background is patterned").isTrue();
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void testSetBackgroundPatternedFalseTablet() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setBackgroundPatterned(false);
+
+ assertThat(getTabletBackground(layout)).isInstanceOf(ColorDrawable.class);
+ assertThat(layout.isBackgroundPatterned()).named("background is patterned").isFalse();
+ }
+
+ @Test
+ public void testNonGlifTheme() {
+ context = new ContextThemeWrapper(application, android.R.style.Theme);
+ new GlifLayout(context);
+ // Inflating with a non-GLIF theme should not crash
+ }
+
+ @Test
+ public void testPeekProgressBarNull() {
+ GlifLayout layout = new GlifLayout(context);
+ assertWithMessage("PeekProgressBar should return null initially")
+ .that(layout.peekProgressBar())
+ .isNull();
+ }
+
+ @Test
+ public void testPeekProgressBar() {
+ GlifLayout layout = new GlifLayout(context);
+ layout.setProgressBarShown(true);
+ assertWithMessage("Peek progress bar should return the bar after setProgressBarShown(true)")
+ .that(layout.peekProgressBar())
+ .isNotNull();
+ }
+
+ @Test
+ public void testMixins() {
+ GlifLayout layout = new GlifLayout(context);
+ final HeaderMixin header = layout.getMixin(HeaderMixin.class);
+ assertThat(header).named("header").isInstanceOf(ColoredHeaderMixin.class);
+
+ assertWithMessage("GlifLayout should have icon mixin")
+ .that(layout.getMixin(IconMixin.class))
+ .isNotNull();
+ assertWithMessage("GlifLayout should have progress bar mixin")
+ .that(layout.getMixin(ProgressBarMixin.class))
+ .isNotNull();
+ }
+
+ @Test
+ public void testInflateFooter() {
+ GlifLayout layout = new GlifLayout(context);
+
+ final View view = layout.inflateFooter(android.R.layout.simple_list_item_1);
+ assertThat(view.getId()).isEqualTo(android.R.id.text1);
+ assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull();
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void testInflateFooterTablet() {
+ testInflateFooter();
+ }
+
+ @Test
+ public void testInflateFooterBlankTemplate() {
+ GlifLayout layout = new GlifLayout(context, R.layout.suw_glif_blank_template);
+
+ final View view = layout.inflateFooter(android.R.layout.simple_list_item_1);
+ assertThat(view.getId()).isEqualTo(android.R.id.text1);
+ assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull();
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void testInflateFooterBlankTemplateTablet() {
+ testInflateFooterBlankTemplate();
+ }
+
+ @Test
+ public void testFooterXml() {
+ GlifLayout layout =
+ new GlifLayout(
+ context,
+ Robolectric.buildAttributeSet()
+ .addAttribute(R.attr.suwFooter, "@android:layout/simple_list_item_1")
+ .build());
+
+ assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull();
+ }
+
+ @Test
+ public void inflateStickyHeader_shouldAddViewToLayout() {
+ GlifLayout layout = new GlifLayout(context);
+
+ final View view = layout.inflateStickyHeader(android.R.layout.simple_list_item_1);
+ assertThat(view.getId()).isEqualTo(android.R.id.text1);
+ assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull();
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void inflateStickyHeader_whenOnTablets_shouldAddViewToLayout() {
+ inflateStickyHeader_shouldAddViewToLayout();
+ }
+
+ @Test
+ public void inflateStickyHeader_whenInXml_shouldAddViewToLayout() {
+ GlifLayout layout =
+ new GlifLayout(
+ context,
+ Robolectric.buildAttributeSet()
+ .addAttribute(R.attr.suwStickyHeader, "@android:layout/simple_list_item_1")
+ .build());
+
+ assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull();
+ }
+
+ @Test
+ public void inflateStickyHeader_whenOnBlankTemplate_shouldAddViewToLayout() {
+ GlifLayout layout = new GlifLayout(context, R.layout.suw_glif_blank_template);
+
+ final View view = layout.inflateStickyHeader(android.R.layout.simple_list_item_1);
+ assertThat(view.getId()).isEqualTo(android.R.id.text1);
+ assertThat((View) layout.findViewById(android.R.id.text1)).isNotNull();
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void inflateStickyHeader_whenOnBlankTemplateTablet_shouldAddViewToLayout() {
+ inflateStickyHeader_whenOnBlankTemplate_shouldAddViewToLayout();
+ }
+
+ @Config(minSdk = Config.OLDEST_SDK, maxSdk = Config.NEWEST_SDK)
+ @Test
+ public void createFromXml_shouldSetLayoutFullscreen_whenLayoutFullscreenIsNotSet() {
+ GlifLayout layout = new GlifLayout(context, Robolectric.buildAttributeSet().build());
+ if (VERSION.SDK_INT >= VERSION_CODES.M) {
+ assertThat(layout.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
+ .isEqualTo(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+ }
+ }
+
+ @Test
+ public void createFromXml_shouldNotSetLayoutFullscreen_whenLayoutFullscreenIsFalse() {
+ GlifLayout layout =
+ new GlifLayout(
+ context,
+ Robolectric.buildAttributeSet()
+ .addAttribute(R.attr.suwLayoutFullscreen, "false")
+ .build());
+
+ assertThat(layout.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN).isEqualTo(0);
+ }
+
+ private Drawable getPhoneBackground(GlifLayout layout) {
+ final StatusBarBackgroundLayout patternBg = layout.findManagedViewById(R.id.suw_pattern_bg);
+ return patternBg.getStatusBarBackground();
+ }
+
+ private Drawable getTabletBackground(GlifLayout layout) {
+ final View patternBg = layout.findManagedViewById(R.id.suw_pattern_bg);
+ return patternBg.getBackground();
+ }
+
+ private void assertDefaultTemplateInflated(GlifLayout layout) {
+ View title = layout.findViewById(R.id.suw_layout_title);
+ assertWithMessage("@id/suw_layout_title should not be null").that(title).isNotNull();
+
+ View icon = layout.findViewById(R.id.suw_layout_icon);
+ assertWithMessage("@id/suw_layout_icon should not be null").that(icon).isNotNull();
+
+ View scrollView = layout.findViewById(R.id.suw_scroll_view);
+ assertWithMessage("@id/suw_scroll_view should be a ScrollView")
+ .that(scrollView instanceof ScrollView)
+ .isTrue();
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java b/library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java
index aa2cce3..ba3e2c5 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/gesture/ConsecutiveTapsGestureDetectorTest.java
@@ -23,96 +23,93 @@ import static org.robolectric.RuntimeEnvironment.application;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
-@RunWith(SuwLibRobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
+@RunWith(RobolectricTestRunner.class)
public class ConsecutiveTapsGestureDetectorTest {
- @Mock
- private ConsecutiveTapsGestureDetector.OnConsecutiveTapsListener mListener;
+ @Mock private ConsecutiveTapsGestureDetector.OnConsecutiveTapsListener listener;
- private ConsecutiveTapsGestureDetector mDetector;
- private int mSlop;
- private int mTapTimeout;
+ private ConsecutiveTapsGestureDetector detector;
+ private int slop;
+ private int tapTimeout;
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
- View view = new View(application);
- view.measure(500, 500);
- view.layout(0, 0, 500, 500);
- mDetector = new ConsecutiveTapsGestureDetector(mListener, view);
+ View view = new View(application);
+ view.measure(500, 500);
+ view.layout(0, 0, 500, 500);
+ detector = new ConsecutiveTapsGestureDetector(listener, view);
- mSlop = ViewConfiguration.get(application).getScaledDoubleTapSlop();
- mTapTimeout = ViewConfiguration.getDoubleTapTimeout();
- }
+ slop = ViewConfiguration.get(application).getScaledDoubleTapSlop();
+ tapTimeout = ViewConfiguration.getDoubleTapTimeout();
+ }
- @Test
- public void onTouchEvent_shouldTriggerCallbackOnFourTaps() {
- InOrder inOrder = inOrder(mListener);
+ @Test
+ public void onTouchEvent_shouldTriggerCallbackOnFourTaps() {
+ InOrder inOrder = inOrder(listener);
- tap(0, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(1));
+ tap(0, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(1));
- tap(100, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(2));
+ tap(100, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(2));
- tap(200, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(3));
+ tap(200, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(3));
- tap(300, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(4));
- }
+ tap(300, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(4));
+ }
- @Test
- public void onTouchEvent_tapOnDifferentLocation_shouldResetCounter() {
- InOrder inOrder = inOrder(mListener);
+ @Test
+ public void onTouchEvent_tapOnDifferentLocation_shouldResetCounter() {
+ InOrder inOrder = inOrder(listener);
- tap(0, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(1));
+ tap(0, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(1));
- tap(100, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(2));
+ tap(100, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(2));
- tap(200, 25f + mSlop * 2, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(1));
+ tap(200, 25f + slop * 2, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(1));
- tap(300, 25f + mSlop * 2, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(2));
- }
+ tap(300, 25f + slop * 2, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(2));
+ }
- @Test
- public void onTouchEvent_tapAfterTimeout_shouldResetCounter() {
- InOrder inOrder = inOrder(mListener);
+ @Test
+ public void onTouchEvent_tapAfterTimeout_shouldResetCounter() {
+ InOrder inOrder = inOrder(listener);
- tap(0, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(1));
+ tap(0, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(1));
- tap(100, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(2));
+ tap(100, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(2));
- tap(200 + mTapTimeout, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(1));
+ tap(200 + tapTimeout, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(1));
- tap(300 + mTapTimeout, 25f, 25f);
- inOrder.verify(mListener).onConsecutiveTaps(eq(2));
- }
+ tap(300 + tapTimeout, 25f, 25f);
+ inOrder.verify(listener).onConsecutiveTaps(eq(2));
+ }
- private void tap(int timeMillis, float x, float y) {
- mDetector.onTouchEvent(
- MotionEvent.obtain(timeMillis, timeMillis, MotionEvent.ACTION_DOWN, x, y, 0));
- mDetector.onTouchEvent(
- MotionEvent.obtain(timeMillis, timeMillis + 10, MotionEvent.ACTION_UP, x, y, 0));
- }
+ private void tap(int timeMillis, float x, float y) {
+ detector.onTouchEvent(
+ MotionEvent.obtain(timeMillis, timeMillis, MotionEvent.ACTION_DOWN, x, y, 0));
+ detector.onTouchEvent(
+ MotionEvent.obtain(timeMillis, timeMillis + 10, MotionEvent.ACTION_UP, x, y, 0));
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java b/library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java
index 40e5da8..b51e875 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/items/ButtonItemTest.java
@@ -16,12 +16,8 @@
package com.android.setupwizardlib.items;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.same;
@@ -31,152 +27,157 @@ import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
import android.content.Context;
-import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-
import com.android.setupwizardlib.R;
import com.android.setupwizardlib.items.ButtonItem.OnClickListener;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
public class ButtonItemTest {
- private ViewGroup mParent;
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
- mParent = new LinearLayout(mContext);
- }
-
- @Test
- public void testDefaultItem() {
- ButtonItem item = new ButtonItem();
-
- assertTrue("ButtonItem should be enabled by default", item.isEnabled());
- assertEquals("ButtonItem should return count = 0", 0, item.getCount());
- assertEquals("ButtonItem should return layout resource = 0", 0, item.getLayoutResource());
- assertEquals("Default theme should be @style/SuwButtonItem", R.style.SuwButtonItem,
- item.getTheme());
- assertNull("Default text should be null", item.getText());
- }
-
- @Test
- public void testOnBindView() {
- ButtonItem item = new ButtonItem();
-
- try {
- item.onBindView(new View(mContext));
- fail("Calling onBindView on ButtonItem should throw UnsupportedOperationException");
- } catch (UnsupportedOperationException e) {
- // pass
- }
- }
-
- @Test
- public void testCreateButton() {
- TestButtonItem item = new TestButtonItem();
- final Button button = item.createButton(mParent);
-
- assertTrue("Default button should be enabled", button.isEnabled());
- assertTrue("Default button text should be empty", TextUtils.isEmpty(button.getText()));
- }
-
- @Test
- public void testButtonItemSetsItsId() {
- TestButtonItem item = new TestButtonItem();
- final int id = 12345;
- item.setId(id);
-
- assertEquals("Button's id should be set", item.createButton(mParent).getId(), id);
- }
-
- @Test
- public void testCreateButtonTwice() {
- TestButtonItem item = new TestButtonItem();
- final Button button = item.createButton(mParent);
-
- FrameLayout frameLayout = new FrameLayout(mContext);
- frameLayout.addView(button);
-
- final Button button2 = item.createButton(mParent);
- assertSame("createButton should be reused", button, button2);
- assertNull("Should be removed from parent after createButton", button2.getParent());
+ private ViewGroup parent;
+ private Context context;
+
+ @Before
+ public void setUp() {
+ context = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
+ parent = new LinearLayout(context);
+ }
+
+ @Test
+ public void testDefaultItem() {
+ ButtonItem item = new ButtonItem();
+
+ assertThat(item.isEnabled()).named("enabled").isTrue();
+ assertThat(item.getCount()).named("count").isEqualTo(0);
+ assertThat(item.getLayoutResource()).named("layout resource").isEqualTo(0);
+ assertThat(item.getTheme()).named("theme").isEqualTo(R.style.SuwButtonItem);
+ assertThat(item.getText()).named("text").isNull();
+ }
+
+ @Test
+ public void testOnBindView() {
+ ButtonItem item = new ButtonItem();
+
+ try {
+ item.onBindView(new View(context));
+ fail("Calling onBindView on ButtonItem should throw UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // pass
}
-
- @Test
- public void testSetEnabledTrue() {
- TestButtonItem item = new TestButtonItem();
- item.setEnabled(true);
-
- final Button button = item.createButton(mParent);
- assertTrue("ButtonItem should be enabled", item.isEnabled());
- assertTrue("Button should be enabled", button.isEnabled());
- }
-
- @Test
- public void testSetEnabledFalse() {
- TestButtonItem item = new TestButtonItem();
- item.setEnabled(false);
-
- final Button button = item.createButton(mParent);
- assertFalse("ButtonItem should be disabled", item.isEnabled());
- assertFalse("Button should be disabled", button.isEnabled());
- }
-
- @Test
- public void testSetText() {
- TestButtonItem item = new TestButtonItem();
- item.setText("lorem ipsum");
-
- final Button button = item.createButton(mParent);
- assertEquals("ButtonItem text should be \"lorem ipsum\"", "lorem ipsum", item.getText());
- assertEquals("Button text should be \"lorem ipsum\"", "lorem ipsum", button.getText());
- }
-
- @Test
- public void testSetTheme() {
- TestButtonItem item = new TestButtonItem();
- item.setTheme(R.style.SuwButtonItem_Colored);
-
- final Button button = item.createButton(mParent);
- assertEquals("ButtonItem theme should be SuwButtonItem.Colored",
- R.style.SuwButtonItem_Colored, item.getTheme());
- assertNotNull(button.getContext().getTheme());
- }
-
- @Test
- public void testOnClickListener() {
- TestButtonItem item = new TestButtonItem();
- final OnClickListener listener = mock(OnClickListener.class);
- item.setOnClickListener(listener);
-
- verify(listener, never()).onClick(any(ButtonItem.class));
-
- final Button button = item.createButton(mParent);
- button.performClick();
-
- verify(listener).onClick(same(item));
- }
-
- private static class TestButtonItem extends ButtonItem {
-
- @Override
- public Button createButton(ViewGroup parent) {
- // Make this method public for testing
- return super.createButton(parent);
- }
+ }
+
+ @Test
+ public void testCreateButton() {
+ TestButtonItem item = new TestButtonItem();
+ final Button button = item.createButton(parent);
+
+ assertThat(button.isEnabled()).named("enabled").isTrue();
+ assertThat(button.getText().toString()).isEmpty();
+ }
+
+ @Test
+ public void testButtonItemSetsItsId() {
+ TestButtonItem item = new TestButtonItem();
+ final int id = 12345;
+ item.setId(id);
+
+ assertWithMessage("Button's id should be set")
+ .that(item.createButton(parent).getId())
+ .isEqualTo(id);
+ }
+
+ @Test
+ public void testCreateButtonTwice() {
+ TestButtonItem item = new TestButtonItem();
+ final Button button = item.createButton(parent);
+
+ FrameLayout frameLayout = new FrameLayout(context);
+ frameLayout.addView(button);
+
+ final Button button2 = item.createButton(parent);
+ assertWithMessage("createButton should be reused").that(button2).isSameAs(button);
+ assertWithMessage("Should be removed from parent after createButton")
+ .that(button2.getParent())
+ .isNull();
+ }
+
+ @Test
+ public void testSetEnabledTrue() {
+ TestButtonItem item = new TestButtonItem();
+ item.setEnabled(true);
+
+ final Button button = item.createButton(parent);
+ assertWithMessage("ButtonItem should be enabled").that(item.isEnabled()).isTrue();
+ assertWithMessage("Button should be enabled").that(button.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void testSetEnabledFalse() {
+ TestButtonItem item = new TestButtonItem();
+ item.setEnabled(false);
+
+ final Button button = item.createButton(parent);
+ assertWithMessage("ButtonItem should be disabled").that(item.isEnabled()).isFalse();
+ assertWithMessage("Button should be disabled").that(button.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void testSetText() {
+ TestButtonItem item = new TestButtonItem();
+ item.setText("lorem ipsum");
+
+ final Button button = item.createButton(parent);
+ assertWithMessage("ButtonItem text should be \"lorem ipsum\"")
+ .that(item.getText().toString())
+ .isEqualTo("lorem ipsum");
+ assertWithMessage("Button text should be \"lorem ipsum\"")
+ .that(button.getText().toString())
+ .isEqualTo("lorem ipsum");
+ }
+
+ @Test
+ public void testSetTheme() {
+ TestButtonItem item = new TestButtonItem();
+ item.setTheme(R.style.SuwButtonItem_Colored);
+
+ final Button button = item.createButton(parent);
+ assertWithMessage("ButtonItem theme should be SuwButtonItem.Colored")
+ .that(item.getTheme())
+ .isEqualTo(R.style.SuwButtonItem_Colored);
+ assertThat(button.getContext().getTheme()).isNotNull();
+ }
+
+ @Test
+ public void testOnClickListener() {
+ TestButtonItem item = new TestButtonItem();
+ final OnClickListener listener = mock(OnClickListener.class);
+ item.setOnClickListener(listener);
+
+ verify(listener, never()).onClick(any(ButtonItem.class));
+
+ final Button button = item.createButton(parent);
+ button.performClick();
+
+ verify(listener).onClick(same(item));
+ }
+
+ 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/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java b/library/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java
index ecaec71..3cbc576 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/items/ItemGroupTest.java
@@ -16,289 +16,308 @@
package com.android.setupwizardlib.items;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
public class ItemGroupTest {
- private static final Item CHILD_1 = new EqualsItem("Child 1");
- private static final Item CHILD_2 = new EqualsItem("Child 2");
- private static final Item CHILD_3 = new EqualsItem("Child 3");
- private static final Item CHILD_4 = new EqualsItem("Child 4");
-
- private ItemGroup mItemGroup;
-
- @Mock
- private ItemHierarchy.Observer mObserver;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mItemGroup = new ItemGroup();
- mItemGroup.registerObserver(mObserver);
- }
-
- @Test
- public void testGroup() {
- mItemGroup.addChild(CHILD_1);
- mItemGroup.addChild(CHILD_2);
-
- assertSame("Item at position 0 should be child1", CHILD_1, mItemGroup.getItemAt(0));
- assertSame("Item at position 1 should be child2", CHILD_2, mItemGroup.getItemAt(1));
- assertEquals("Should have 2 children", 2, mItemGroup.getCount());
-
- final InOrder inOrder = inOrder(mObserver);
- inOrder.verify(mObserver).onItemRangeInserted(eq(mItemGroup), eq(0), eq(1));
- inOrder.verify(mObserver).onItemRangeInserted(eq(mItemGroup), eq(1), eq(1));
- }
-
- @Test
- public void testRemoveChild() {
- mItemGroup.addChild(CHILD_1);
- mItemGroup.addChild(CHILD_2);
- mItemGroup.addChild(CHILD_3);
-
- mItemGroup.removeChild(CHILD_2);
-
- assertSame("Item at position 0 should be child1", CHILD_1, mItemGroup.getItemAt(0));
- assertSame("Item at position 1 should be child3", CHILD_3, mItemGroup.getItemAt(1));
- assertEquals("Should have 2 children", 2, mItemGroup.getCount());
-
- verify(mObserver).onItemRangeRemoved(eq(mItemGroup), eq(1), eq(1));
- }
-
- @Test
- public void testClear() {
- mItemGroup.addChild(CHILD_1);
- mItemGroup.addChild(CHILD_2);
-
- mItemGroup.clear();
-
- assertEquals("Should have 0 child", 0, mItemGroup.getCount());
-
- verify(mObserver).onItemRangeRemoved(eq(mItemGroup), eq(0), eq(2));
- }
-
- @Test
- public void testNestedGroup() {
- ItemGroup parentGroup = new ItemGroup();
- ItemGroup childGroup = new ItemGroup();
- parentGroup.registerObserver(mObserver);
-
- parentGroup.addChild(CHILD_1);
- childGroup.addChild(CHILD_2);
- childGroup.addChild(CHILD_3);
- parentGroup.addChild(childGroup);
- parentGroup.addChild(CHILD_4);
-
- assertSame("Position 0 should be child 1", CHILD_1, parentGroup.getItemAt(0));
- assertSame("Position 1 should be child 2", CHILD_2, parentGroup.getItemAt(1));
- assertSame("Position 2 should be child 3", CHILD_3, parentGroup.getItemAt(2));
- assertSame("Position 3 should be child 4", CHILD_4, parentGroup.getItemAt(3));
-
- final InOrder inOrder = inOrder(mObserver);
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(1));
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(1), eq(2));
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(3), eq(1));
- verifyNoMoreInteractions(mObserver);
- }
-
- @Test
- public void testNestedGroupClearNotification() {
- ItemGroup parentGroup = new ItemGroup();
- ItemGroup childGroup = new ItemGroup();
- parentGroup.registerObserver(mObserver);
-
- parentGroup.addChild(CHILD_1);
- childGroup.addChild(CHILD_2);
- childGroup.addChild(CHILD_3);
- parentGroup.addChild(childGroup);
- parentGroup.addChild(CHILD_4);
-
- childGroup.clear();
-
- final InOrder inOrder = inOrder(mObserver);
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(1));
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(1), eq(2));
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(3), eq(1));
- verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(1), eq(2));
- verifyNoMoreInteractions(mObserver);
- }
-
- @Test
- public void testNestedGroupRemoveNotification() {
- ItemGroup parentGroup = new ItemGroup();
- ItemGroup childGroup = new ItemGroup();
- parentGroup.registerObserver(mObserver);
-
- parentGroup.addChild(CHILD_1);
- childGroup.addChild(CHILD_2);
- childGroup.addChild(CHILD_3);
- parentGroup.addChild(childGroup);
- parentGroup.addChild(CHILD_4);
-
- childGroup.removeChild(CHILD_3);
- childGroup.removeChild(CHILD_2);
-
- final InOrder inOrder = inOrder(mObserver);
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(1));
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(1), eq(2));
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(3), eq(1));
- inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(2), eq(1));
- inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(1), eq(1));
- verifyNoMoreInteractions(mObserver);
+ private static final Item CHILD_1 = new EqualsItem("Child 1");
+ private static final Item CHILD_2 = new EqualsItem("Child 2");
+ private static final Item CHILD_3 = new EqualsItem("Child 3");
+ private static final Item CHILD_4 = new EqualsItem("Child 4");
+
+ private ItemGroup itemGroup;
+
+ @Mock private ItemHierarchy.Observer observer;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ itemGroup = new ItemGroup();
+ itemGroup.registerObserver(observer);
+ }
+
+ @Test
+ public void testGroup() {
+ itemGroup.addChild(CHILD_1);
+ itemGroup.addChild(CHILD_2);
+
+ assertWithMessage("Item at position 0 should be child1")
+ .that(itemGroup.getItemAt(0))
+ .isSameAs(CHILD_1);
+ assertWithMessage("Item at position 1 should be child2")
+ .that(itemGroup.getItemAt(1))
+ .isSameAs(CHILD_2);
+ assertWithMessage("Should have 2 children").that(itemGroup.getCount()).isEqualTo(2);
+
+ final InOrder inOrder = inOrder(observer);
+ inOrder.verify(observer).onItemRangeInserted(eq(itemGroup), eq(0), eq(1));
+ inOrder.verify(observer).onItemRangeInserted(eq(itemGroup), eq(1), eq(1));
+ }
+
+ @Test
+ public void testRemoveChild() {
+ itemGroup.addChild(CHILD_1);
+ itemGroup.addChild(CHILD_2);
+ itemGroup.addChild(CHILD_3);
+
+ itemGroup.removeChild(CHILD_2);
+
+ assertWithMessage("Item at position 0 should be child1")
+ .that(itemGroup.getItemAt(0))
+ .isSameAs(CHILD_1);
+ assertWithMessage("Item at position 1 should be child3")
+ .that(itemGroup.getItemAt(1))
+ .isSameAs(CHILD_3);
+ assertWithMessage("Should have 2 children").that(itemGroup.getCount()).isEqualTo(2);
+
+ verify(observer).onItemRangeRemoved(eq(itemGroup), eq(1), eq(1));
+ }
+
+ @Test
+ public void testClear() {
+ itemGroup.addChild(CHILD_1);
+ itemGroup.addChild(CHILD_2);
+
+ itemGroup.clear();
+
+ assertWithMessage("Should have 0 child").that(itemGroup.getCount()).isEqualTo(0);
+
+ verify(observer).onItemRangeRemoved(eq(itemGroup), eq(0), eq(2));
+ }
+
+ @Test
+ public void testNestedGroup() {
+ ItemGroup parentGroup = new ItemGroup();
+ ItemGroup childGroup = new ItemGroup();
+ parentGroup.registerObserver(observer);
+
+ parentGroup.addChild(CHILD_1);
+ childGroup.addChild(CHILD_2);
+ childGroup.addChild(CHILD_3);
+ parentGroup.addChild(childGroup);
+ parentGroup.addChild(CHILD_4);
+
+ assertWithMessage("Position 0 should be child 1")
+ .that(parentGroup.getItemAt(0))
+ .isSameAs(CHILD_1);
+ assertWithMessage("Position 1 should be child 2")
+ .that(parentGroup.getItemAt(1))
+ .isSameAs(CHILD_2);
+ assertWithMessage("Position 2 should be child 3")
+ .that(parentGroup.getItemAt(2))
+ .isSameAs(CHILD_3);
+ assertWithMessage("Position 3 should be child 4")
+ .that(parentGroup.getItemAt(3))
+ .isSameAs(CHILD_4);
+
+ final InOrder inOrder = inOrder(observer);
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(1));
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(1), eq(2));
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(3), eq(1));
+ verifyNoMoreInteractions(observer);
+ }
+
+ @Test
+ public void testNestedGroupClearNotification() {
+ ItemGroup parentGroup = new ItemGroup();
+ ItemGroup childGroup = new ItemGroup();
+ parentGroup.registerObserver(observer);
+
+ parentGroup.addChild(CHILD_1);
+ childGroup.addChild(CHILD_2);
+ childGroup.addChild(CHILD_3);
+ parentGroup.addChild(childGroup);
+ parentGroup.addChild(CHILD_4);
+
+ childGroup.clear();
+
+ final InOrder inOrder = inOrder(observer);
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(1));
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(1), eq(2));
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(3), eq(1));
+ verify(observer).onItemRangeRemoved(eq(parentGroup), eq(1), eq(2));
+ verifyNoMoreInteractions(observer);
+ }
+
+ @Test
+ public void testNestedGroupRemoveNotification() {
+ ItemGroup parentGroup = new ItemGroup();
+ ItemGroup childGroup = new ItemGroup();
+ parentGroup.registerObserver(observer);
+
+ parentGroup.addChild(CHILD_1);
+ childGroup.addChild(CHILD_2);
+ childGroup.addChild(CHILD_3);
+ parentGroup.addChild(childGroup);
+ parentGroup.addChild(CHILD_4);
+
+ childGroup.removeChild(CHILD_3);
+ childGroup.removeChild(CHILD_2);
+
+ final InOrder inOrder = inOrder(observer);
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(1));
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(1), eq(2));
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(3), eq(1));
+ inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(2), eq(1));
+ inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(1), eq(1));
+ verifyNoMoreInteractions(observer);
+ }
+
+ @Test
+ public void testNestedGroupClear() {
+ ItemGroup parentGroup = new ItemGroup();
+ ItemGroup childGroup = new ItemGroup();
+ parentGroup.registerObserver(observer);
+
+ parentGroup.addChild(CHILD_1);
+ childGroup.addChild(CHILD_2);
+ childGroup.addChild(CHILD_3);
+ parentGroup.addChild(childGroup);
+
+ childGroup.clear();
+
+ final InOrder inOrder = inOrder(observer);
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(1));
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(1), eq(2));
+ inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(1), eq(2));
+ verifyNoMoreInteractions(observer);
+ }
+
+ @Test
+ public void testNestedGroupRemoveLastChild() {
+ ItemGroup parentGroup = new ItemGroup();
+ ItemGroup childGroup1 = new ItemGroup();
+ ItemGroup childGroup2 = new ItemGroup();
+ parentGroup.registerObserver(observer);
+
+ childGroup1.addChild(CHILD_1);
+ childGroup1.addChild(CHILD_2);
+ parentGroup.addChild(childGroup1);
+ childGroup2.addChild(CHILD_3);
+ childGroup2.addChild(CHILD_4);
+ parentGroup.addChild(childGroup2);
+
+ childGroup2.removeChild(CHILD_4);
+ childGroup2.removeChild(CHILD_3);
+
+ final InOrder inOrder = inOrder(observer);
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(2));
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(2), eq(2));
+ inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(3), eq(1));
+ inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(2), eq(1));
+ verifyNoMoreInteractions(observer);
+ }
+
+ @Test
+ public void testNestedGroupClearOnlyChild() {
+ ItemGroup parentGroup = new ItemGroup();
+ ItemGroup childGroup = new ItemGroup();
+ parentGroup.registerObserver(observer);
+
+ childGroup.addChild(CHILD_1);
+ childGroup.addChild(CHILD_2);
+ parentGroup.addChild(childGroup);
+
+ childGroup.clear();
+
+ final InOrder inOrder = inOrder(observer);
+ inOrder.verify(observer).onItemRangeInserted(eq(parentGroup), eq(0), eq(2));
+ inOrder.verify(observer).onItemRangeRemoved(eq(parentGroup), eq(0), eq(2));
+ verifyNoMoreInteractions(observer);
+ }
+
+ @Test
+ public void testNotifyChange() {
+ itemGroup.addChild(CHILD_1);
+ itemGroup.addChild(CHILD_2);
+
+ CHILD_2.setTitle("Child 2 modified");
+
+ verify(observer).onItemRangeChanged(eq(itemGroup), eq(1), eq(1));
+ }
+
+ @Test
+ public void testEmptyChildGroup() {
+ ItemGroup parentGroup = new ItemGroup();
+ ItemGroup childGroup = new ItemGroup();
+
+ parentGroup.addChild(CHILD_1);
+ parentGroup.addChild(childGroup);
+ parentGroup.addChild(CHILD_2);
+
+ assertWithMessage("Position 0 should be child 1")
+ .that(parentGroup.getItemAt(0))
+ .isSameAs(CHILD_1);
+ assertWithMessage("Position 1 should be child 2")
+ .that(parentGroup.getItemAt(1))
+ .isSameAs(CHILD_2);
+ }
+
+ @Test
+ public void testFindItemById() {
+ CHILD_1.setId(12345);
+ CHILD_2.setId(23456);
+
+ itemGroup.addChild(CHILD_1);
+ itemGroup.addChild(CHILD_2);
+
+ assertWithMessage("Find item 23456 should return child 2")
+ .that(itemGroup.findItemById(23456))
+ .isSameAs(CHILD_2);
+ }
+
+ @Test
+ public void testFindItemByIdNotFound() {
+ CHILD_1.setId(12345);
+ CHILD_2.setId(23456);
+
+ itemGroup.addChild(CHILD_1);
+ itemGroup.addChild(CHILD_2);
+
+ assertWithMessage("ID not found should return null")
+ .that(itemGroup.findItemById(56789))
+ .isNull();
+ }
+
+ /**
+ * This class will always return true on {@link #equals(Object)}. Used to ensure that ItemGroup is
+ * using identity rather than equals(). Be sure to use assertSame rather than assertEquals when
+ * comparing items of this class.
+ */
+ private static class EqualsItem extends Item {
+
+ EqualsItem(String name) {
+ setTitle(name);
}
- @Test
- public void testNestedGroupClear() {
- ItemGroup parentGroup = new ItemGroup();
- ItemGroup childGroup = new ItemGroup();
- parentGroup.registerObserver(mObserver);
-
- parentGroup.addChild(CHILD_1);
- childGroup.addChild(CHILD_2);
- childGroup.addChild(CHILD_3);
- parentGroup.addChild(childGroup);
-
- childGroup.clear();
-
- final InOrder inOrder = inOrder(mObserver);
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(1));
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(1), eq(2));
- inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(1), eq(2));
- verifyNoMoreInteractions(mObserver);
- }
-
- @Test
- public void testNestedGroupRemoveLastChild() {
- ItemGroup parentGroup = new ItemGroup();
- ItemGroup childGroup1 = new ItemGroup();
- ItemGroup childGroup2 = new ItemGroup();
- parentGroup.registerObserver(mObserver);
-
- childGroup1.addChild(CHILD_1);
- childGroup1.addChild(CHILD_2);
- parentGroup.addChild(childGroup1);
- childGroup2.addChild(CHILD_3);
- childGroup2.addChild(CHILD_4);
- parentGroup.addChild(childGroup2);
-
- childGroup2.removeChild(CHILD_4);
- childGroup2.removeChild(CHILD_3);
-
- final InOrder inOrder = inOrder(mObserver);
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(2));
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(2), eq(2));
- inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(3), eq(1));
- inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(2), eq(1));
- verifyNoMoreInteractions(mObserver);
- }
-
- @Test
- public void testNestedGroupClearOnlyChild() {
- ItemGroup parentGroup = new ItemGroup();
- ItemGroup childGroup = new ItemGroup();
- parentGroup.registerObserver(mObserver);
-
- childGroup.addChild(CHILD_1);
- childGroup.addChild(CHILD_2);
- parentGroup.addChild(childGroup);
-
- childGroup.clear();
-
- final InOrder inOrder = inOrder(mObserver);
- inOrder.verify(mObserver).onItemRangeInserted(eq(parentGroup), eq(0), eq(2));
- inOrder.verify(mObserver).onItemRangeRemoved(eq(parentGroup), eq(0), eq(2));
- verifyNoMoreInteractions(mObserver);
- }
-
- @Test
- public void testNotifyChange() {
- mItemGroup.addChild(CHILD_1);
- mItemGroup.addChild(CHILD_2);
-
- CHILD_2.setTitle("Child 2 modified");
-
- verify(mObserver).onItemRangeChanged(eq(mItemGroup), eq(1), eq(1));
- }
-
- @Test
- public void testEmptyChildGroup() {
- ItemGroup parentGroup = new ItemGroup();
- ItemGroup childGroup = new ItemGroup();
-
- parentGroup.addChild(CHILD_1);
- parentGroup.addChild(childGroup);
- parentGroup.addChild(CHILD_2);
-
- assertSame("Position 0 should be child 1", CHILD_1, parentGroup.getItemAt(0));
- assertSame("Position 1 should be child 2", CHILD_2, parentGroup.getItemAt(1));
+ @Override
+ public int hashCode() {
+ return 1;
}
- @Test
- public void testFindItemById() {
- CHILD_1.setId(12345);
- CHILD_2.setId(23456);
-
- mItemGroup.addChild(CHILD_1);
- mItemGroup.addChild(CHILD_2);
-
- assertSame("Find item 23456 should return child 2",
- CHILD_2, mItemGroup.findItemById(23456));
- }
-
- @Test
- public void testFindItemByIdNotFound() {
- CHILD_1.setId(12345);
- CHILD_2.setId(23456);
-
- mItemGroup.addChild(CHILD_1);
- mItemGroup.addChild(CHILD_2);
-
- assertNull("ID not found should return null", mItemGroup.findItemById(56789));
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof Item;
}
- /**
- * This class will always return true on {@link #equals(Object)}. Used to ensure that ItemGroup
- * is using identity rather than equals(). Be sure to use assertSame rather than assertEquals
- * when comparing items of this class.
- */
- private static class EqualsItem extends Item {
-
- EqualsItem(String name) {
- setTitle(name);
- }
-
- @Override
- public int hashCode() {
- return 1;
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof Item;
- }
-
- @Override
- public String toString() {
- return "EqualsItem{title=" + getTitle() + "}";
- }
+ @Override
+ public String toString() {
+ return "EqualsItem{title=" + getTitle() + "}";
}
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/robolectric/ExternalResources.java b/library/test/robotest/src/com/android/setupwizardlib/robolectric/ExternalResources.java
new file mode 100644
index 0000000..06ef508
--- /dev/null
+++ b/library/test/robotest/src/com/android/setupwizardlib/robolectric/ExternalResources.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.setupwizardlib.robolectric;
+
+import static org.robolectric.RuntimeEnvironment.application;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import androidx.annotation.AnyRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import android.util.DisplayMetrics;
+import java.util.HashMap;
+import java.util.Map;
+import org.robolectric.res.ResName;
+import org.robolectric.res.ResType;
+import org.robolectric.res.TypedResource;
+import org.robolectric.shadows.ShadowPackageManager;
+
+/**
+ * Utility class to inject resources for an "external" application in Robolectric tests. This can be
+ * used with {@link org.robolectric.shadows.ShadowPackageManager#resources} to simulate loading
+ * resources from another package.
+ */
+public final class ExternalResources {
+
+ public static Resources injectExternalResources(String packageName) {
+ return injectExternalResources(createPackageInfo(packageName));
+ }
+
+ public static Resources injectExternalResources(PackageInfo packageInfo) {
+ try {
+ application.getPackageManager().getPackageInfo(packageInfo.packageName, 0);
+ } catch (NameNotFoundException e) {
+ // Add the package if it does not exist
+ shadowOf(application.getPackageManager()).addPackage(packageInfo);
+ }
+ Resources resources = Resources.forPackageName(packageInfo.packageName);
+ ShadowPackageManager.resources.put(packageInfo.packageName, resources);
+ return resources;
+ }
+
+ /**
+ * Constructed resources for testing, representing resources external to the current package under
+ * test.
+ */
+ public static class Resources extends android.content.res.Resources {
+
+ private final String packageName;
+
+ public static Resources forPackageName(String packageName) {
+ android.content.res.Resources res = application.getResources();
+ return new Resources(
+ packageName, res.getAssets(), res.getDisplayMetrics(), res.getConfiguration());
+ }
+
+ private Resources(
+ String packageName, AssetManager assets, DisplayMetrics metrics, Configuration config) {
+ super(assets, metrics, config);
+ this.packageName = packageName;
+ }
+
+ @Override
+ public int getIdentifier(String name, String defType, String defPackage) {
+ Integer resourceId = resourceIds.get(ResName.qualifyResName(name, defPackage, defType));
+ if (resourceId == null) {
+ return 0;
+ }
+ return resourceId;
+ }
+
+ @Override
+ public int getInteger(int id) {
+ return (int) get(id, ResType.INTEGER);
+ }
+
+ public void putInteger(String name, int value) {
+ put(
+ ResName.qualifyResName(name, packageName, "integer"),
+ new TypedResource<>(value, ResType.INTEGER, null));
+ }
+
+ @Override
+ public int getColor(int id) {
+ return (int) get(id, ResType.COLOR);
+ }
+
+ @Override
+ public int getColor(int id, @Nullable Theme theme) {
+ return (int) get(id, ResType.COLOR);
+ }
+
+ public void putColor(String name, int value) {
+ put(
+ ResName.qualifyResName(name, packageName, "color"),
+ new TypedResource<>(value, ResType.COLOR, null));
+ }
+
+ @NonNull
+ @Override
+ public CharSequence getText(int id) {
+ return (CharSequence) get(id, ResType.CHAR_SEQUENCE);
+ }
+
+ @NonNull
+ @Override
+ public String getString(int id) {
+ return get(id, ResType.CHAR_SEQUENCE).toString();
+ }
+
+ public void putText(String name, CharSequence value) {
+ put(
+ ResName.qualifyResName(name, packageName, "string"),
+ new TypedResource<>(value, ResType.CHAR_SEQUENCE, null));
+ }
+
+ private final Map<Integer, TypedResource<?>> overrideResources = new HashMap<>();
+ private final Map<ResName, Integer> resourceIds = new HashMap<>();
+ private int nextId = 1;
+
+ private <T> void put(ResName resName, TypedResource<T> value) {
+ int id = nextId++;
+ overrideResources.put(id, value);
+ resourceIds.put(resName, id);
+ }
+
+ private Object get(@AnyRes int id, ResType type) {
+ TypedResource<?> override = overrideResources.get(id);
+ if (override != null && override.getResType() == type) {
+ return override.getData();
+ }
+ throw new NotFoundException();
+ }
+ }
+
+ private static PackageInfo createPackageInfo(String packageName) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ return packageInfo;
+ }
+
+ private ExternalResources() {}
+}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/robolectric/SuwLibRobolectricTestRunner.java b/library/test/robotest/src/com/android/setupwizardlib/robolectric/SuwLibRobolectricTestRunner.java
deleted file mode 100644
index 61baa23..0000000
--- a/library/test/robotest/src/com/android/setupwizardlib/robolectric/SuwLibRobolectricTestRunner.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.robolectric;
-
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.InitializationError;
-import org.robolectric.RobolectricTestRunner;
-
-public class SuwLibRobolectricTestRunner extends RobolectricTestRunner {
-
- public SuwLibRobolectricTestRunner(Class<?> testClass) throws InitializationError {
- super(testClass);
- }
-
- @Override
- protected void runChild(FrameworkMethod method, RunNotifier notifier) {
- System.out.println("===== Running " + method + " =====");
- super.runChild(method, notifier);
- }
-}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowLog.java b/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowLog.java
deleted file mode 100644
index f1d37c8..0000000
--- a/library/test/robotest/src/com/android/setupwizardlib/shadow/ShadowLog.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.setupwizardlib.shadow;
-
-import android.util.Log;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-@Implements(Log.class)
-public class ShadowLog extends org.robolectric.shadows.ShadowLog {
-
- public static boolean sWtfIsFatal = true;
-
- public static class TerribleFailure extends RuntimeException {
-
- public TerribleFailure(String msg, Throwable cause) {
- super(msg, cause);
- }
- }
-
- @Implementation
- public static void wtf(String tag, String msg) {
- org.robolectric.shadows.ShadowLog.wtf(tag, msg);
- if (sWtfIsFatal) {
- throw new TerribleFailure(msg, null);
- }
- }
-
- @Implementation
- public static void wtf(String tag, String msg, Throwable throwable) {
- org.robolectric.shadows.ShadowLog.wtf(tag, msg, throwable);
- if (sWtfIsFatal) {
- throw new TerribleFailure(msg, throwable);
- }
- }
-}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java b/library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java
index 3aafa7d..3bc9fd1 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/span/LinkSpanTest.java
@@ -17,8 +17,7 @@
package com.android.setupwizardlib.span;
import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertSame;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.robolectric.RuntimeEnvironment.application;
import android.content.Context;
@@ -27,82 +26,83 @@ import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.widget.TextView;
-
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
-@RunWith(SuwLibRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
public class LinkSpanTest {
- @Test
- public void onClick_shouldCallListenerOnContext() {
- final TestContext context = new TestContext(application);
- final TextView textView = new TextView(context);
- final LinkSpan linkSpan = new LinkSpan("test_id");
-
- linkSpan.onClick(textView);
-
- assertSame("Clicked LinkSpan should be passed to setup", linkSpan, context.clickedSpan);
- }
-
- @Test
- public void onClick_contextDoesNotImplementOnClickListener_shouldBeNoOp() {
- final TextView textView = new TextView(application);
- final LinkSpan linkSpan = new LinkSpan("test_id");
-
- linkSpan.onClick(textView);
-
- // This would be no-op, because the context doesn't implement LinkSpan.OnClickListener.
- // Just check that no uncaught exception here.
+ @Test
+ public void onClick_shouldCallListenerOnContext() {
+ final TestContext context = new TestContext(application);
+ final TextView textView = new TextView(context);
+ final LinkSpan linkSpan = new LinkSpan("test_id");
+
+ linkSpan.onClick(textView);
+
+ assertWithMessage("Clicked LinkSpan should be passed to setup")
+ .that(context.clickedSpan)
+ .isSameAs(linkSpan);
+ }
+
+ @Test
+ public void onClick_contextDoesNotImplementOnClickListener_shouldBeNoOp() {
+ final TextView textView = new TextView(application);
+ final LinkSpan linkSpan = new LinkSpan("test_id");
+
+ linkSpan.onClick(textView);
+
+ // This would be no-op, because the context doesn't implement LinkSpan.OnClickListener.
+ // Just check that no uncaught exception here.
+ }
+
+ @Test
+ public void onClick_contextWrapsOnClickListener_shouldCallWrappedListener() {
+ final TestContext context = new TestContext(application);
+ final Context wrapperContext = new ContextWrapper(context);
+ final TextView textView = new TextView(wrapperContext);
+ final LinkSpan linkSpan = new LinkSpan("test_id");
+
+ linkSpan.onClick(textView);
+ assertWithMessage("Clicked LinkSpan should be passed to setup")
+ .that(context.clickedSpan)
+ .isSameAs(linkSpan);
+ }
+
+ @Test
+ public void onClick_shouldClearSelection() {
+ final TestContext context = new TestContext(application);
+ final TextView textView = new TextView(context);
+ textView.setMovementMethod(LinkMovementMethod.getInstance());
+ textView.setFocusable(true);
+ textView.setFocusableInTouchMode(true);
+ final LinkSpan linkSpan = new LinkSpan("test_id");
+
+ SpannableStringBuilder text = new SpannableStringBuilder("Lorem ipsum dolor sit");
+ textView.setText(text);
+ text.setSpan(linkSpan, /* start= */ 0, /* end= */ 5, /* flags= */ 0);
+ // Simulate the touch effect set by TextView when touched.
+ Selection.setSelection(text, /* start= */ 0, /* stop= */ 5);
+
+ linkSpan.onClick(textView);
+
+ assertThat(Selection.getSelectionStart(textView.getText())).isEqualTo(0);
+ assertThat(Selection.getSelectionEnd(textView.getText())).isEqualTo(0);
+ }
+
+ @SuppressWarnings("deprecation")
+ private static class TestContext extends ContextWrapper implements LinkSpan.OnClickListener {
+
+ public LinkSpan clickedSpan = null;
+
+ TestContext(Context base) {
+ super(base);
}
- @Test
- public void onClick_contextWrapsOnClickListener_shouldCallWrappedListener() {
- final TestContext context = new TestContext(application);
- final Context wrapperContext = new ContextWrapper(context);
- final TextView textView = new TextView(wrapperContext);
- final LinkSpan linkSpan = new LinkSpan("test_id");
-
-
- linkSpan.onClick(textView);
- assertSame("Clicked LinkSpan should be passed to setup", linkSpan, context.clickedSpan);
- }
-
- @Test
- public void onClick_shouldClearSelection() {
- final TestContext context = new TestContext(application);
- final TextView textView = new TextView(context);
- textView.setMovementMethod(LinkMovementMethod.getInstance());
- textView.setFocusable(true);
- textView.setFocusableInTouchMode(true);
- final LinkSpan linkSpan = new LinkSpan("test_id");
-
- SpannableStringBuilder text = new SpannableStringBuilder("Lorem ipsum dolor sit");
- textView.setText(text);
- text.setSpan(linkSpan, /* start= */ 0, /* end= */ 5, /* flags= */ 0);
- // Simulate the touch effect set by TextView when touched.
- Selection.setSelection(text, /* start= */ 0, /* end= */ 5);
-
- linkSpan.onClick(textView);
-
- assertThat(Selection.getSelectionStart(textView.getText())).isEqualTo(0);
- assertThat(Selection.getSelectionEnd(textView.getText())).isEqualTo(0);
- }
-
- @SuppressWarnings("deprecation")
- private static class TestContext extends ContextWrapper implements LinkSpan.OnClickListener {
-
- public LinkSpan clickedSpan = null;
-
- TestContext(Context base) {
- super(base);
- }
-
- @Override
- public void onClick(LinkSpan span) {
- clickedSpan = span;
- }
+ @Override
+ public void onClick(LinkSpan span) {
+ clickedSpan = span;
}
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java b/library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java
index ec3622d..9b99a68 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/template/ListViewScrollHandlingDelegateTest.java
@@ -16,105 +16,93 @@
package com.android.setupwizardlib.template;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ListView;
-
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
-@RunWith(SuwLibRobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
+@RunWith(RobolectricTestRunner.class)
public class ListViewScrollHandlingDelegateTest {
- @Mock
- private RequireScrollMixin mRequireScrollMixin;
+ @Mock private RequireScrollMixin requireScrollMixin;
- private ListView mListView;
- private ListViewScrollHandlingDelegate mDelegate;
- private ArgumentCaptor<OnScrollListener> mListenerCaptor;
+ private ListView listView;
+ private ListViewScrollHandlingDelegate delegate;
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
- mListView = spy(new TestListView(application));
- mDelegate = new ListViewScrollHandlingDelegate(mRequireScrollMixin, mListView);
+ listView = new TestListView(application);
+ delegate = new ListViewScrollHandlingDelegate(requireScrollMixin, listView);
- mListenerCaptor = ArgumentCaptor.forClass(OnScrollListener.class);
- doNothing().when(mListView).setOnScrollListener(mListenerCaptor.capture());
+ listView.layout(0, 0, 50, 50);
+ }
- mListView.layout(0, 0, 50, 50);
- }
+ @Test
+ public void testRequireScroll() throws Throwable {
+ delegate.startListening();
- @Test
- public void testRequireScroll() throws Throwable {
- mDelegate.startListening();
+ verify(requireScrollMixin).notifyScrollabilityChange(true);
+ }
- verify(mRequireScrollMixin).notifyScrollabilityChange(true);
- }
+ @Test
+ public void testScrolledToBottom() throws Throwable {
+ delegate.startListening();
- @Test
- public void testScrolledToBottom() throws Throwable {
- mDelegate.startListening();
+ verify(requireScrollMixin).notifyScrollabilityChange(true);
- verify(mRequireScrollMixin).notifyScrollabilityChange(true);
+ Shadows.shadowOf(listView).getOnScrollListener().onScroll(listView, 2, 20, 20);
- doReturn(20).when(mListView).getLastVisiblePosition();
- mListenerCaptor.getValue().onScroll(mListView, 2, 20, 20);
+ verify(requireScrollMixin).notifyScrollabilityChange(false);
+ }
- verify(mRequireScrollMixin).notifyScrollabilityChange(false);
- }
+ @Test
+ public void testPageScrollDown() throws Throwable {
+ delegate.pageScrollDown();
+ assertThat(Shadows.shadowOf(listView).getLastSmoothScrollByDistance()).isEqualTo(50);
+ }
- @Test
- public void testPageScrollDown() throws Throwable {
- mDelegate.pageScrollDown();
- verify(mListView).smoothScrollBy(eq(50), anyInt());
- }
+ private static class TestListView extends ListView {
+
+ TestListView(Context context) {
+ super(context);
+ setAdapter(
+ new BaseAdapter() {
+ @Override
+ public int getCount() {
+ return 20;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
- private static class TestListView extends ListView {
-
- TestListView(Context context) {
- super(context);
- setAdapter(new BaseAdapter() {
- @Override
- public int getCount() {
- return 20;
- }
-
- @Override
- public Object getItem(int position) {
- return null;
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- return new View(parent.getContext());
- }
- });
- }
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return new View(parent.getContext());
+ }
+ });
}
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java b/library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java
index c641449..fe45d5f 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/template/RequireScrollMixinTest.java
@@ -16,13 +16,10 @@
package com.android.setupwizardlib.template;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -33,135 +30,138 @@ import android.annotation.SuppressLint;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
-
+import com.android.setupwizardlib.GlifLayout;
import com.android.setupwizardlib.TemplateLayout;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
import com.android.setupwizardlib.template.RequireScrollMixin.OnRequireScrollStateChangedListener;
import com.android.setupwizardlib.template.RequireScrollMixin.ScrollHandlingDelegate;
import com.android.setupwizardlib.view.NavigationBar;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
-@RunWith(SuwLibRobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
+@RunWith(RobolectricTestRunner.class)
public class RequireScrollMixinTest {
- @Mock
- private TemplateLayout mTemplateLayout;
-
- @Mock
- private ScrollHandlingDelegate mDelegate;
-
- private RequireScrollMixin mRequireScrollMixin;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- doReturn(application).when(mTemplateLayout).getContext();
- mRequireScrollMixin = new RequireScrollMixin(mTemplateLayout);
- mRequireScrollMixin.setScrollHandlingDelegate(mDelegate);
- }
-
- @Test
- public void testRequireScroll() {
- mRequireScrollMixin.requireScroll();
-
- verify(mDelegate).startListening();
- }
-
- @Test
- public void testScrollStateChangedListener() {
- OnRequireScrollStateChangedListener listener =
- mock(OnRequireScrollStateChangedListener.class);
- mRequireScrollMixin.setOnRequireScrollStateChangedListener(listener);
- assertFalse("Scrolling should not be required initially",
- mRequireScrollMixin.isScrollingRequired());
-
- mRequireScrollMixin.notifyScrollabilityChange(true);
- verify(listener).onRequireScrollStateChanged(true);
- assertTrue("Scrolling should be required when there is more content below the fold",
- mRequireScrollMixin.isScrollingRequired());
-
- mRequireScrollMixin.notifyScrollabilityChange(false);
- verify(listener).onRequireScrollStateChanged(false);
- assertFalse("Scrolling should not be required after scrolling to bottom",
- mRequireScrollMixin.isScrollingRequired());
-
- // Once the user has scrolled to the bottom, they should not be forced to scroll down again
- mRequireScrollMixin.notifyScrollabilityChange(true);
- verifyNoMoreInteractions(listener);
-
- assertFalse("Scrolling should not be required after scrolling to bottom once",
- mRequireScrollMixin.isScrollingRequired());
-
- assertSame(listener, mRequireScrollMixin.getOnRequireScrollStateChangedListener());
- }
-
- @Test
- public void testCreateOnClickListener() {
- OnClickListener wrappedListener = mock(OnClickListener.class);
- final OnClickListener onClickListener =
- mRequireScrollMixin.createOnClickListener(wrappedListener);
-
- mRequireScrollMixin.notifyScrollabilityChange(true);
- onClickListener.onClick(null);
-
- verify(wrappedListener, never()).onClick(any(View.class));
- verify(mDelegate).pageScrollDown();
-
- mRequireScrollMixin.notifyScrollabilityChange(false);
- onClickListener.onClick(null);
-
- verify(wrappedListener).onClick(any(View.class));
- }
-
- @Test
- public void testRequireScrollWithNavigationBar() {
- final NavigationBar navigationBar = new NavigationBar(application);
- mRequireScrollMixin.requireScrollWithNavigationBar(navigationBar);
-
- mRequireScrollMixin.notifyScrollabilityChange(true);
- assertEquals("More button should be visible",
- View.VISIBLE, navigationBar.getMoreButton().getVisibility());
- assertEquals("Next button should be hidden",
- View.GONE, navigationBar.getNextButton().getVisibility());
-
- navigationBar.getMoreButton().performClick();
- verify(mDelegate).pageScrollDown();
-
- mRequireScrollMixin.notifyScrollabilityChange(false);
- assertEquals("More button should be hidden",
- View.GONE, navigationBar.getMoreButton().getVisibility());
- assertEquals("Next button should be visible",
- View.VISIBLE, navigationBar.getNextButton().getVisibility());
- }
-
- @SuppressLint("SetTextI18n") // It's OK for testing
- @Test
- public void testRequireScrollWithButton() {
- final Button button = new Button(application);
- button.setText("OriginalLabel");
- OnClickListener wrappedListener = mock(OnClickListener.class);
- mRequireScrollMixin.requireScrollWithButton(
- button, "TestMoreLabel", wrappedListener);
-
- assertEquals("Button label should be kept initially", "OriginalLabel", button.getText());
-
- mRequireScrollMixin.notifyScrollabilityChange(true);
- assertEquals("TestMoreLabel", button.getText());
- button.performClick();
- verify(wrappedListener, never()).onClick(eq(button));
- verify(mDelegate).pageScrollDown();
-
- mRequireScrollMixin.notifyScrollabilityChange(false);
- assertEquals("OriginalLabel", button.getText());
- button.performClick();
- verify(wrappedListener).onClick(eq(button));
- }
+ @Mock private ScrollHandlingDelegate delegate;
+
+ private RequireScrollMixin requireScrollMixin;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ TemplateLayout templateLayout = new GlifLayout(application);
+ requireScrollMixin = new RequireScrollMixin(templateLayout);
+ requireScrollMixin.setScrollHandlingDelegate(delegate);
+ }
+
+ @Test
+ public void testRequireScroll() {
+ requireScrollMixin.requireScroll();
+
+ verify(delegate).startListening();
+ }
+
+ @Test
+ public void testScrollStateChangedListener() {
+ OnRequireScrollStateChangedListener listener = mock(OnRequireScrollStateChangedListener.class);
+ requireScrollMixin.setOnRequireScrollStateChangedListener(listener);
+ assertWithMessage("Scrolling should not be required initially")
+ .that(requireScrollMixin.isScrollingRequired())
+ .isFalse();
+
+ requireScrollMixin.notifyScrollabilityChange(true);
+ verify(listener).onRequireScrollStateChanged(true);
+ assertWithMessage("Scrolling should be required when there is more content below the fold")
+ .that(requireScrollMixin.isScrollingRequired())
+ .isTrue();
+
+ requireScrollMixin.notifyScrollabilityChange(false);
+ verify(listener).onRequireScrollStateChanged(false);
+ assertWithMessage("Scrolling should not be required after scrolling to bottom")
+ .that(requireScrollMixin.isScrollingRequired())
+ .isFalse();
+
+ // Once the user has scrolled to the bottom, they should not be forced to scroll down again
+ requireScrollMixin.notifyScrollabilityChange(true);
+ verifyNoMoreInteractions(listener);
+
+ assertWithMessage("Scrolling should not be required after scrolling to bottom once")
+ .that(requireScrollMixin.isScrollingRequired())
+ .isFalse();
+
+ assertThat(requireScrollMixin.getOnRequireScrollStateChangedListener()).isSameAs(listener);
+ }
+
+ @Test
+ public void testCreateOnClickListener() {
+ OnClickListener wrappedListener = mock(OnClickListener.class);
+ final OnClickListener onClickListener =
+ requireScrollMixin.createOnClickListener(wrappedListener);
+
+ requireScrollMixin.notifyScrollabilityChange(true);
+ onClickListener.onClick(null);
+
+ verify(wrappedListener, never()).onClick(any(View.class));
+ verify(delegate).pageScrollDown();
+
+ requireScrollMixin.notifyScrollabilityChange(false);
+ onClickListener.onClick(null);
+
+ verify(wrappedListener).onClick(any(View.class));
+ }
+
+ @Test
+ public void testRequireScrollWithNavigationBar() {
+ final NavigationBar navigationBar = new NavigationBar(application);
+ requireScrollMixin.requireScrollWithNavigationBar(navigationBar);
+
+ requireScrollMixin.notifyScrollabilityChange(true);
+ assertWithMessage("More button should be visible")
+ .that(navigationBar.getMoreButton().getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertWithMessage("Next button should be hidden")
+ .that(navigationBar.getNextButton().getVisibility())
+ .isEqualTo(View.GONE);
+
+ navigationBar.getMoreButton().performClick();
+ verify(delegate).pageScrollDown();
+
+ requireScrollMixin.notifyScrollabilityChange(false);
+ assertWithMessage("More button should be hidden")
+ .that(navigationBar.getMoreButton().getVisibility())
+ .isEqualTo(View.GONE);
+ assertWithMessage("Next button should be visible")
+ .that(navigationBar.getNextButton().getVisibility())
+ .isEqualTo(View.VISIBLE);
+ }
+
+ @SuppressLint("SetTextI18n") // It's OK for testing
+ @Test
+ public void testRequireScrollWithButton() {
+ final Button button = new Button(application);
+ button.setText("OriginalLabel");
+ OnClickListener wrappedListener = mock(OnClickListener.class);
+ requireScrollMixin.requireScrollWithButton(button, "TestMoreLabel", wrappedListener);
+
+ assertWithMessage("Button label should be kept initially")
+ .that(button.getText().toString())
+ .isEqualTo("OriginalLabel");
+
+ requireScrollMixin.notifyScrollabilityChange(true);
+ assertThat(button.getText().toString()).isEqualTo("TestMoreLabel");
+ button.performClick();
+ verify(wrappedListener, never()).onClick(eq(button));
+ verify(delegate).pageScrollDown();
+
+ requireScrollMixin.notifyScrollabilityChange(false);
+ assertThat(button.getText().toString()).isEqualTo("OriginalLabel");
+ button.performClick();
+ verify(wrappedListener).onClick(eq(button));
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java b/library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java
index 429445c..b07e2a3 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/template/ScrollViewScrollHandlingDelegateTest.java
@@ -16,72 +16,65 @@
package com.android.setupwizardlib.template;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.spy;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
+import android.view.View;
import com.android.setupwizardlib.view.BottomScrollView;
-import com.android.setupwizardlib.view.BottomScrollView.BottomScrollListener;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
-@RunWith(SuwLibRobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
+@RunWith(RobolectricTestRunner.class)
public class ScrollViewScrollHandlingDelegateTest {
- @Mock
- private RequireScrollMixin mRequireScrollMixin;
-
- private BottomScrollView mScrollView;
- private ScrollViewScrollHandlingDelegate mDelegate;
- private ArgumentCaptor<BottomScrollListener> mListenerCaptor;
+ @Mock private RequireScrollMixin requireScrollMixin;
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
+ private BottomScrollView scrollView;
+ private ScrollViewScrollHandlingDelegate delegate;
- mScrollView = spy(new BottomScrollView(application));
- mDelegate = new ScrollViewScrollHandlingDelegate(mRequireScrollMixin, mScrollView);
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
- mListenerCaptor = ArgumentCaptor.forClass(BottomScrollListener.class);
- doNothing().when(mScrollView).setBottomScrollListener(mListenerCaptor.capture());
+ scrollView = new BottomScrollView(application);
+ View childView = new View(application);
+ scrollView.addView(childView);
+ delegate = new ScrollViewScrollHandlingDelegate(requireScrollMixin, scrollView);
- mScrollView.layout(0, 0, 50, 50);
- }
+ scrollView.layout(0, 0, 500, 500);
+ childView.layout(0, 0, 1000, 1000);
+ }
- @Test
- public void testRequireScroll() throws Throwable {
- mDelegate.startListening();
+ @Test
+ public void testRequireScroll() throws Throwable {
+ delegate.startListening();
- mListenerCaptor.getValue().onRequiresScroll();
- verify(mRequireScrollMixin).notifyScrollabilityChange(true);
- }
+ scrollView.getBottomScrollListener().onRequiresScroll();
+ verify(requireScrollMixin).notifyScrollabilityChange(true);
+ }
- @Test
- public void testScrolledToBottom() throws Throwable {
- mDelegate.startListening();
+ @Test
+ public void testScrolledToBottom() throws Throwable {
+ delegate.startListening();
- mListenerCaptor.getValue().onRequiresScroll();
- verify(mRequireScrollMixin).notifyScrollabilityChange(true);
+ scrollView.getBottomScrollListener().onRequiresScroll();
+ verify(requireScrollMixin).notifyScrollabilityChange(true);
- mListenerCaptor.getValue().onScrolledToBottom();
+ scrollView.getBottomScrollListener().onScrolledToBottom();
- verify(mRequireScrollMixin).notifyScrollabilityChange(false);
- }
+ verify(requireScrollMixin).notifyScrollabilityChange(false);
+ }
- @Test
- public void testPageScrollDown() throws Throwable {
- mDelegate.pageScrollDown();
- verify(mScrollView).smoothScrollBy(anyInt(), eq(50));
- }
+ @Test
+ public void testPageScrollDown() throws Throwable {
+ delegate.pageScrollDown();
+ assertThat(scrollView.getScrollY()).isEqualTo(500);
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java
index c10c122..a0c688c 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/util/GlifDimensionTest.java
@@ -16,7 +16,7 @@
package com.android.setupwizardlib.util;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.robolectric.RuntimeEnvironment.application;
import android.content.Context;
@@ -25,90 +25,88 @@ import android.content.res.TypedArray;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
-
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.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
@Config(sdk = Config.ALL_SDKS)
public class GlifDimensionTest {
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
- }
-
- @Test
- public void testDividerInsetPhone() {
- assertDividerInset();
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void testDividerInsetSw600dp() {
- assertDividerInset();
- }
-
- private void assertDividerInset() {
- final Resources res = mContext.getResources();
-
- final TypedArray a = mContext.obtainStyledAttributes(new int[]{R.attr.suwMarginSides});
- final int marginSides = a.getDimensionPixelSize(0, 0);
- a.recycle();
-
- assertEquals(
- "Dimensions should satisfy constraint: "
- + "?attr/suwMarginSides = suw_items_glif_text_divider_inset",
- marginSides,
- res.getDimensionPixelSize(R.dimen.suw_items_glif_text_divider_inset));
-
- assertEquals(
- "Dimensions should satisfy constraint: ?attr/suwMarginSides + "
- + "suw_items_icon_container_width = suw_items_glif_icon_divider_inset",
- marginSides + res.getDimensionPixelSize(R.dimen.suw_items_icon_container_width),
- res.getDimensionPixelSize(R.dimen.suw_items_glif_icon_divider_inset));
- }
-
- @Test
- public void testButtonMargin() {
- assertButtonMargin();
- }
-
- @Config(qualifiers = "sw600dp")
- @Test
- public void testButtonMarginSw600dp() {
- assertButtonMargin();
- }
-
- private void assertButtonMargin() {
- final Resources res = mContext.getResources();
-
- final TypedArray a = mContext.obtainStyledAttributes(new int[]{R.attr.suwMarginSides});
- final int marginSides = a.getDimensionPixelSize(0, 0);
- a.recycle();
-
- assertEquals(
- "Dimensions should satisfy constraint: ?attr/suwMarginSides - "
- + "4dp (internal padding of button) = suw_glif_button_margin_end",
- marginSides - dp2Px(4),
- res.getDimensionPixelSize(R.dimen.suw_glif_button_margin_end));
-
- assertEquals(
- "Dimensions should satisfy constraint: ?attr/suwMarginSides - "
- + "suw_glif_button_padding = suw_glif_button_margin_start",
- marginSides - res.getDimensionPixelSize(R.dimen.suw_glif_button_padding),
- res.getDimensionPixelSize(R.dimen.suw_glif_button_margin_start));
- }
-
- private int dp2Px(float dp) {
- DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
- return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics);
- }
+ private Context context;
+
+ @Before
+ public void setUp() {
+ context = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
+ }
+
+ @Test
+ public void testDividerInsetPhone() {
+ assertDividerInset();
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void testDividerInsetSw600dp() {
+ assertDividerInset();
+ }
+
+ private void assertDividerInset() {
+ final Resources res = context.getResources();
+
+ final TypedArray a = context.obtainStyledAttributes(new int[] {R.attr.suwMarginSides});
+ final int marginSides = a.getDimensionPixelSize(0, 0);
+ a.recycle();
+
+ assertWithMessage(
+ "Dimensions should satisfy constraint: "
+ + "?attr/suwMarginSides = suw_items_glif_text_divider_inset")
+ .that(res.getDimensionPixelSize(R.dimen.suw_items_glif_text_divider_inset))
+ .isEqualTo(marginSides);
+
+ assertWithMessage(
+ "Dimensions should satisfy constraint: ?attr/suwMarginSides + "
+ + "suw_items_icon_container_width = suw_items_glif_icon_divider_inset")
+ .that(res.getDimensionPixelSize(R.dimen.suw_items_glif_icon_divider_inset))
+ .isEqualTo(marginSides + res.getDimensionPixelSize(R.dimen.suw_items_icon_container_width));
+ }
+
+ @Test
+ public void testButtonMargin() {
+ assertButtonMargin();
+ }
+
+ @Config(qualifiers = "sw600dp")
+ @Test
+ public void testButtonMarginSw600dp() {
+ assertButtonMargin();
+ }
+
+ private void assertButtonMargin() {
+ final Resources res = context.getResources();
+
+ final TypedArray a = context.obtainStyledAttributes(new int[] {R.attr.suwMarginSides});
+ final int marginSides = a.getDimensionPixelSize(0, 0);
+ a.recycle();
+
+ assertWithMessage(
+ "Dimensions should satisfy constraint: ?attr/suwMarginSides - "
+ + "4dp (internal padding of button) = suw_glif_button_margin_end")
+ .that(res.getDimensionPixelSize(R.dimen.suw_glif_button_margin_end))
+ .isEqualTo(marginSides - dp2Px(4));
+
+ assertWithMessage(
+ "Dimensions should satisfy constraint: ?attr/suwMarginSides - "
+ + "suw_glif_button_padding = suw_glif_button_margin_start")
+ .that(res.getDimensionPixelSize(R.dimen.suw_glif_button_margin_start))
+ .isEqualTo(marginSides - res.getDimensionPixelSize(R.dimen.suw_glif_button_padding));
+ }
+
+ private int dp2Px(float dp) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, displayMetrics);
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java
index d8e318d..61b84bb 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/util/GlifStyleTest.java
@@ -17,9 +17,6 @@
package com.android.setupwizardlib.util;
import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.robolectric.RuntimeEnvironment.application;
import android.annotation.TargetApi;
@@ -28,71 +25,82 @@ import android.content.Context;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import androidx.annotation.Nullable;
+import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
+import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
-
-import androidx.annotation.Nullable;
-
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.Robolectric;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+import org.robolectric.util.ReflectionHelpers.ClassParameter;
-@RunWith(SuwLibRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
public class GlifStyleTest {
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light);
+ @Test
+ public void testSuwGlifButtonTertiary() {
+ Button button =
+ createButton(
+ new ContextThemeWrapper(application, R.style.SuwThemeGlif_Light),
+ Robolectric.buildAttributeSet()
+ .setStyleAttribute("@style/SuwGlifButton.Tertiary")
+ .build());
+ assertThat(button.getBackground()).named("background").isNotNull();
+ assertThat(button.getTransformationMethod()).named("transformation method").isNull();
+ if (VERSION.SDK_INT < VERSION_CODES.M) {
+ // Robolectric resolved the wrong theme attribute on versions >= M
+ // https://github.com/robolectric/robolectric/issues/2940
+ assertThat(Integer.toHexString(button.getTextColors().getDefaultColor()))
+ .isEqualTo("ff4285f4");
}
-
- @Test
- public void testSuwGlifButtonTertiary() {
- Button button = new Button(
- mContext,
- Robolectric.buildAttributeSet()
- .setStyleAttribute("@style/SuwGlifButton.Tertiary")
- .build());
- assertThat(button.getBackground()).named("background").isNotNull();
- assertThat(button.getTransformationMethod()).named("transformation method").isNull();
- if (VERSION.SDK_INT < VERSION_CODES.M) {
- // Robolectric resolved the wrong theme attribute on versions >= M
- // https://github.com/robolectric/robolectric/issues/2940
- assertEquals("ff4285f4", Integer.toHexString(button.getTextColors().getDefaultColor()));
- }
+ }
+
+ @TargetApi(VERSION_CODES.LOLLIPOP)
+ @Config(sdk = Config.NEWEST_SDK)
+ @Test
+ public void glifThemeLight_statusBarColorShouldBeTransparent() {
+ GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class);
+ assertThat(activity.getWindow().getStatusBarColor()).isEqualTo(0x00000000);
+ }
+
+ @Test
+ public void glifLoadingScreen_shouldHaveProgressBar() {
+ GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class);
+ activity.setContentView(R.layout.suw_glif_loading_screen);
+
+ assertThat((View) activity.findViewById(R.id.suw_large_progress_bar))
+ .isInstanceOf(ProgressBar.class);
+ }
+
+ private Button createButton(Context context, AttributeSet attrs) {
+ Class<? extends Button> buttonClass;
+ try {
+ // Use AppCompatButton in builds that have them (i.e. gingerbreadCompat)
+ // noinspection unchecked
+ buttonClass =
+ (Class<? extends Button>) Class.forName("androidx.appcompat.widget.AppCompatButton");
+ } catch (ClassNotFoundException e) {
+ buttonClass = Button.class;
}
-
- @TargetApi(VERSION_CODES.LOLLIPOP)
- @Config(sdk = Config.NEWEST_SDK)
- @Test
- public void glifThemeLight_statusBarColorShouldBeTransparent() {
- GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class);
- assertEquals(0x00000000, activity.getWindow().getStatusBarColor());
- }
-
- @Test
- public void glifLoadingScreen_shouldHaveProgressBar() {
- GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class);
- activity.setContentView(R.layout.suw_glif_loading_screen);
-
- assertTrue("Progress bar should exist",
- activity.findViewById(R.id.suw_large_progress_bar) instanceof ProgressBar);
- }
-
- private static class GlifThemeActivity extends Activity {
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- setTheme(R.style.SuwThemeGlif_Light);
- super.onCreate(savedInstanceState);
- }
+ return ReflectionHelpers.callConstructor(
+ buttonClass,
+ ClassParameter.from(Context.class, context),
+ ClassParameter.from(AttributeSet.class, attrs));
+ }
+
+ private static class GlifThemeActivity extends Activity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ setTheme(R.style.SuwThemeGlif_Light);
+ super.onCreate(savedInstanceState);
}
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java
index 44b8886..13e29f6 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/util/GlifV3StyleTest.java
@@ -18,68 +18,59 @@ package com.android.setupwizardlib.util;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
import android.app.Activity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import androidx.annotation.Nullable;
import android.view.View;
import android.widget.Button;
-
-import androidx.annotation.Nullable;
-
import com.android.setupwizardlib.R;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
@Config(minSdk = Config.OLDEST_SDK, maxSdk = Config.NEWEST_SDK)
public class GlifV3StyleTest {
- @Test
- public void activityWithGlifV3Theme_shouldUseLightNavBarOnV27OrAbove() {
- GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class);
- if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
- assertEquals(
- activity.getWindow().getNavigationBarColor(),
- Color.WHITE);
- int vis = activity.getWindow().getDecorView().getSystemUiVisibility();
- assertTrue((vis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0);
- } else if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
- assertEquals(
- activity.getWindow().getNavigationBarColor(),
- Color.BLACK);
- }
- // Nav bar color is not customizable pre-L
+ @Test
+ public void activityWithGlifV3Theme_shouldUseLightNavBarOnV27OrAbove() {
+ GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class);
+ if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) {
+ assertThat(activity.getWindow().getNavigationBarColor()).isEqualTo(Color.WHITE);
+ int vis = activity.getWindow().getDecorView().getSystemUiVisibility();
+ assertThat((vis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0).isTrue();
+ } else if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ assertThat(activity.getWindow().getNavigationBarColor()).isEqualTo(Color.BLACK);
}
+ // Nav bar color is not customizable pre-L
+ }
- @Test
- public void buttonWithGlifV3_shouldBeGoogleSans() {
- GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class);
- Button button = new Button(
- activity,
- Robolectric.buildAttributeSet()
- .setStyleAttribute("@style/SuwGlifButton.Primary")
- .build());
- assertThat(button.getTypeface()).isEqualTo(Typeface.create("google-sans", 0));
- // Button should not be all caps
- assertThat(button.getTransformationMethod()).isNull();
- }
+ @Test
+ public void buttonWithGlifV3_shouldBeGoogleSans() {
+ GlifThemeActivity activity = Robolectric.setupActivity(GlifThemeActivity.class);
+ Button button =
+ new Button(
+ activity,
+ Robolectric.buildAttributeSet()
+ .setStyleAttribute("@style/SuwGlifButton.Primary")
+ .build());
+ assertThat(button.getTypeface()).isEqualTo(Typeface.create("google-sans", 0));
+ // Button should not be all caps
+ assertThat(button.getTransformationMethod()).isNull();
+ }
- private static class GlifThemeActivity extends Activity {
+ private static class GlifThemeActivity extends Activity {
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- setTheme(R.style.SuwThemeGlifV3_Light);
- super.onCreate(savedInstanceState);
- }
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ setTheme(R.style.SuwThemeGlifV3_Light);
+ super.onCreate(savedInstanceState);
}
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java
index 2285cd5..f301e43 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/util/PartnerTest.java
@@ -17,211 +17,164 @@
package com.android.setupwizardlib.util;
import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
import static org.robolectric.RuntimeEnvironment.application;
+import static org.robolectric.Shadows.shadowOf;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
-
import com.android.setupwizardlib.R;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
+import com.android.setupwizardlib.robolectric.ExternalResources;
+import com.android.setupwizardlib.robolectric.ExternalResources.Resources;
import com.android.setupwizardlib.util.Partner.ResourceEntry;
-import com.android.setupwizardlib.util.PartnerTest.ShadowApplicationPackageManager;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.Shadows;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowResources;
-import java.util.Arrays;
-import java.util.Collections;
-
-@RunWith(SuwLibRobolectricTestRunner.class)
-@Config(
- sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK },
- shadows = ShadowApplicationPackageManager.class)
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
public class PartnerTest {
- private static final String ACTION_PARTNER_CUSTOMIZATION =
- "com.android.setupwizard.action.PARTNER_CUSTOMIZATION";
-
- private Context mContext;
- private Resources mPartnerResources;
-
- private ShadowApplicationPackageManager mPackageManager;
-
- @Before
- public void setUp() throws Exception {
- Partner.resetForTesting();
-
- mContext = spy(application);
- mPartnerResources = spy(ShadowResources.getSystem());
-
- mPackageManager =
- (ShadowApplicationPackageManager) Shadows.shadowOf(application.getPackageManager());
- mPackageManager.partnerResources = mPartnerResources;
- }
-
- @Test
- public void testLoadPartner() {
- mPackageManager.addResolveInfoForIntent(
- new Intent(ACTION_PARTNER_CUSTOMIZATION),
- Arrays.asList(
- createResolveInfo("foo.bar", false, true),
- createResolveInfo("test.partner.package", true, true))
- );
-
- Partner partner = Partner.get(mContext);
- assertNotNull("Partner should not be null", partner);
- }
-
- @Test
- public void testLoadNoPartner() {
- Partner partner = Partner.get(mContext);
- assertNull("Partner should be null", partner);
- }
-
- @Test
- public void testLoadNonSystemPartner() {
- mPackageManager.addResolveInfoForIntent(
- new Intent(ACTION_PARTNER_CUSTOMIZATION),
- Arrays.asList(
- createResolveInfo("foo.bar", false, true),
- createResolveInfo("test.partner.package", false, true))
- );
-
- Partner partner = Partner.get(mContext);
- assertNull("Partner should be null", partner);
- }
-
- @Test
- public void testLoadPartnerValue() {
- doReturn(0x7f010000).when(mPartnerResources)
- .getIdentifier(eq("suwTransitionDuration"), eq("integer"), anyString());
- doReturn(5000).when(mPartnerResources).getInteger(eq(0x7f010000));
-
- mPackageManager.addResolveInfoForIntent(
- new Intent(ACTION_PARTNER_CUSTOMIZATION),
- Arrays.asList(
- createResolveInfo("foo.bar", false, true),
- createResolveInfo("test.partner.package", true, true))
- );
-
- ResourceEntry entry = Partner.getResourceEntry(mContext, R.integer.suwTransitionDuration);
- int partnerValue = entry.resources.getInteger(entry.id);
- assertEquals("Partner value should be overlaid to 5000", 5000, partnerValue);
- assertTrue("Partner value should come from overlay", entry.isOverlay);
- }
-
- @Test
- public void getColor_shouldReturnPartnerValueIfPresent() {
- final int expectedPartnerColor = 1111;
- doReturn(12345).when(mPartnerResources)
- .getIdentifier(eq("suw_color_accent_dark"), eq("color"), anyString());
- doReturn(expectedPartnerColor).when(mPartnerResources).getColor(eq(12345));
- mPackageManager.addResolveInfoForIntent(
- new Intent(ACTION_PARTNER_CUSTOMIZATION),
- Arrays.asList(createResolveInfo("test.partner.package", true, true)));
- final int foundColor = Partner.getColor(mContext, R.color.suw_color_accent_dark);
- assertEquals("Partner color should be overlayed to: " + expectedPartnerColor,
- expectedPartnerColor, foundColor);
- }
-
- @Test
- public void getText_shouldReturnPartnerValueIfPresent() {
- final CharSequence expectedPartnerText = "partner";
- doReturn(12345).when(mPartnerResources)
- .getIdentifier(eq("suw_next_button_label"), eq("string"), anyString());
- doReturn(expectedPartnerText).when(mPartnerResources).getText(eq(12345));
- mPackageManager.addResolveInfoForIntent(
- new Intent(ACTION_PARTNER_CUSTOMIZATION),
- Collections.singletonList(createResolveInfo("test.partner.package", true, true)));
- final CharSequence partnerText = Partner.getText(mContext, R.string.suw_next_button_label);
- assertThat(partnerText).isEqualTo(expectedPartnerText);
+ private static final String ACTION_PARTNER_CUSTOMIZATION =
+ "com.android.setupwizard.action.PARTNER_CUSTOMIZATION";
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ Partner.resetForTesting();
+ }
+
+ @Test
+ public void get_withPartnerPackage_shouldReturnNonNull() {
+ new PartnerPackageBuilder("foo.bar")
+ .setIsSystem(false)
+ .setDirectBootAware(true)
+ .injectResources();
+ new PartnerPackageBuilder("test.partner.package").setDirectBootAware(true).injectResources();
+
+ Partner partner = Partner.get(application);
+ assertThat(partner).isNotNull();
+ assertThat(partner.getPackageName()).isEqualTo("test.partner.package");
+ }
+
+ @Test
+ public void get_noPartnerPackage_shouldReturnNull() {
+ Partner partner = Partner.get(application);
+ assertThat(partner).isNull();
+ }
+
+ @Test
+ public void get_nonSystemPartnerPackage_shouldIgnoreAndReturnNull() {
+ new PartnerPackageBuilder("foo.bar")
+ .setIsSystem(false)
+ .setDirectBootAware(true)
+ .injectResources();
+ new PartnerPackageBuilder("test.partner.package")
+ .setIsSystem(false)
+ .setDirectBootAware(true)
+ .injectResources();
+
+ Partner partner = Partner.get(application);
+ assertThat(partner).isNull();
+ }
+
+ @Test
+ public void getResourceEntry_hasOverlay_shouldReturnOverlayValue() {
+ new PartnerPackageBuilder("test.partner.package")
+ .injectResources()
+ .putInteger("suwTransitionDuration", 5000);
+
+ ResourceEntry entry = Partner.getResourceEntry(application, R.integer.suwTransitionDuration);
+ int partnerValue = entry.resources.getInteger(entry.id);
+ assertThat(partnerValue).named("partner value").isEqualTo(5000);
+ assertThat(entry.isOverlay).isTrue();
+ }
+
+ @Test
+ public void getColor_partnerValuePresent_shouldReturnPartnerValue() {
+ new PartnerPackageBuilder("test.partner.package")
+ .injectResources()
+ .putColor("suw_color_accent_dark", 0xffff00ff);
+
+ final int color = Partner.getColor(application, R.color.suw_color_accent_dark);
+ assertThat(color).isEqualTo(0xffff00ff);
+ }
+
+ @Test
+ public void getText_partnerValuePresent_shouldReturnPartnerValue() {
+ new PartnerPackageBuilder("test.partner.package")
+ .injectResources()
+ .putText("suw_next_button_label", "partner");
+
+ final CharSequence partnerText = Partner.getText(application, R.string.suw_next_button_label);
+ assertThat(partnerText.toString()).isEqualTo("partner");
+ }
+
+ @Test
+ public void getResourceEntry_partnerValueNotPresent_shouldReturnDefault() {
+ new PartnerPackageBuilder("test.partner.package").injectResources();
+
+ ResourceEntry entry = Partner.getResourceEntry(application, R.color.suw_color_accent_dark);
+ int partnerValue = entry.resources.getColor(entry.id);
+ assertThat(partnerValue).isEqualTo(0xff448aff);
+ assertThat(entry.isOverlay).isFalse();
+ }
+
+ @Test
+ public void getResourceEntry_directBootUnawareNoValueDefined_shouldReturnDefaultValue() {
+ new PartnerPackageBuilder("test.partner.package").injectResources();
+
+ ResourceEntry entry = Partner.getResourceEntry(application, R.color.suw_color_accent_dark);
+ int partnerValue = entry.resources.getColor(entry.id);
+ assertThat(partnerValue).isEqualTo(0xff448aff);
+ assertThat(entry.isOverlay).isFalse();
+ }
+
+ private static class PartnerPackageBuilder {
+ private final String packageName;
+ private final ResolveInfo resolveInfo;
+
+ PartnerPackageBuilder(String packageName) {
+ this.packageName = packageName;
+
+ resolveInfo = new ResolveInfo();
+ resolveInfo.resolvePackageName = packageName;
+ ActivityInfo activityInfo = new ActivityInfo();
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+ appInfo.packageName = packageName;
+ activityInfo.applicationInfo = appInfo;
+ activityInfo.packageName = packageName;
+ activityInfo.name = packageName;
+ resolveInfo.activityInfo = activityInfo;
}
- @Test
- public void testLoadDefaultValue() {
- mPackageManager.addResolveInfoForIntent(
- new Intent(ACTION_PARTNER_CUSTOMIZATION),
- Arrays.asList(
- createResolveInfo("foo.bar", false, true),
- createResolveInfo("test.partner.package", true, true))
- );
-
- ResourceEntry entry = Partner.getResourceEntry(mContext, R.color.suw_color_accent_dark);
- int partnerValue = entry.resources.getColor(entry.id);
- assertEquals("Partner value should default to 0xff448aff", 0xff448aff, partnerValue);
- assertFalse("Partner value should come from fallback", entry.isOverlay);
- }
-
- @Test
- public void testNotDirectBootAware() {
- mPackageManager.addResolveInfoForIntent(
- new Intent(ACTION_PARTNER_CUSTOMIZATION),
- Collections.singletonList(createResolveInfo("test.partner.package", true, false)));
-
- ResourceEntry entry = Partner.getResourceEntry(mContext, R.color.suw_color_accent_dark);
- int partnerValue = entry.resources.getColor(entry.id);
- assertEquals("Partner value should default to 0xff448aff", 0xff448aff, partnerValue);
- assertFalse("Partner value should come from fallback", entry.isOverlay);
+ PartnerPackageBuilder setIsSystem(boolean isSystem) {
+ if (isSystem) {
+ resolveInfo.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ } else {
+ resolveInfo.activityInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
+ }
+ return this;
}
- private ResolveInfo createResolveInfo(
- String packageName,
- boolean isSystem,
- boolean directBootAware) {
- ResolveInfo info = new ResolveInfo();
- info.resolvePackageName = packageName;
- ActivityInfo activityInfo = new ActivityInfo();
- ApplicationInfo appInfo = new ApplicationInfo();
- appInfo.flags = isSystem ? ApplicationInfo.FLAG_SYSTEM : 0;
- appInfo.packageName = packageName;
- activityInfo.applicationInfo = appInfo;
- activityInfo.packageName = packageName;
- activityInfo.name = packageName;
- if (VERSION.SDK_INT >= VERSION_CODES.N) {
- activityInfo.directBootAware = directBootAware;
- }
- info.activityInfo = activityInfo;
- return info;
+ PartnerPackageBuilder setDirectBootAware(boolean directBootAware) {
+ if (VERSION.SDK_INT >= VERSION_CODES.N) {
+ resolveInfo.activityInfo.directBootAware = directBootAware;
+ }
+ return this;
}
- @Implements(className = "android.app.ApplicationPackageManager")
- public static class ShadowApplicationPackageManager extends
- org.robolectric.shadows.ShadowApplicationPackageManager {
-
- public Resources partnerResources;
-
- @Implementation
- @Override
- public Resources getResourcesForApplication(ApplicationInfo app)
- throws NameNotFoundException {
- if (app != null && "test.partner.package".equals(app.packageName)) {
- return partnerResources;
- } else {
- return super.getResourcesForApplication(app);
- }
- }
+ Resources injectResources() {
+ shadowOf(application.getPackageManager())
+ .addResolveInfoForIntent(new Intent(ACTION_PARTNER_CUSTOMIZATION), resolveInfo);
+ return ExternalResources.injectExternalResources(packageName);
}
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/ThemeResolverTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/ThemeResolverTest.java
new file mode 100644
index 0000000..6489961
--- /dev/null
+++ b/library/test/robotest/src/com/android/setupwizardlib/util/ThemeResolverTest.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.setupwizardlib.util;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.app.Activity;
+import android.content.Intent;
+import androidx.annotation.StyleRes;
+import com.android.setupwizardlib.R;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = Config.NEWEST_SDK)
+public class ThemeResolverTest {
+
+ @After
+ public void resetDefaultThemeResolver() {
+ ThemeResolver.setDefault(null);
+ }
+
+ @Test
+ public void resolve_nonDayNight_shouldReturnCorrespondingTheme() {
+ @StyleRes int defaultTheme = 12345;
+ ThemeResolver themeResolver =
+ new ThemeResolver.Builder().setDefaultTheme(defaultTheme).setUseDayNight(false).build();
+ assertThat(themeResolver.resolve("material")).isEqualTo(R.style.SuwThemeMaterial);
+ assertThat(themeResolver.resolve("material_light")).isEqualTo(R.style.SuwThemeMaterial_Light);
+ assertThat(themeResolver.resolve("glif")).isEqualTo(R.style.SuwThemeGlif);
+ assertThat(themeResolver.resolve("glif_light")).isEqualTo(R.style.SuwThemeGlif_Light);
+ assertThat(themeResolver.resolve("glif_v2")).isEqualTo(R.style.SuwThemeGlifV2);
+ assertThat(themeResolver.resolve("glif_v2_light")).isEqualTo(R.style.SuwThemeGlifV2_Light);
+ assertThat(themeResolver.resolve("glif_v3")).isEqualTo(R.style.SuwThemeGlifV3);
+ assertThat(themeResolver.resolve("glif_v3_light")).isEqualTo(R.style.SuwThemeGlifV3_Light);
+ assertThat(themeResolver.resolve("unknown_theme")).isEqualTo(defaultTheme);
+ }
+
+ @Test
+ public void resolve_dayNight_shouldReturnDayNightTheme() {
+ @StyleRes int defaultTheme = 12345;
+ ThemeResolver themeResolver = new ThemeResolver.Builder().setDefaultTheme(defaultTheme).build();
+ assertThat(themeResolver.resolve("material")).isEqualTo(R.style.SuwThemeMaterial_DayNight);
+ assertThat(themeResolver.resolve("material_light"))
+ .isEqualTo(R.style.SuwThemeMaterial_DayNight);
+ assertThat(themeResolver.resolve("glif")).isEqualTo(R.style.SuwThemeGlif_DayNight);
+ assertThat(themeResolver.resolve("glif_light")).isEqualTo(R.style.SuwThemeGlif_DayNight);
+ assertThat(themeResolver.resolve("glif_v2")).isEqualTo(R.style.SuwThemeGlifV2_DayNight);
+ assertThat(themeResolver.resolve("glif_v2_light")).isEqualTo(R.style.SuwThemeGlifV2_DayNight);
+ assertThat(themeResolver.resolve("glif_v3")).isEqualTo(R.style.SuwThemeGlifV3_DayNight);
+ assertThat(themeResolver.resolve("glif_v3_light")).isEqualTo(R.style.SuwThemeGlifV3_DayNight);
+ assertThat(themeResolver.resolve("unknown_theme")).isEqualTo(defaultTheme);
+ }
+
+ @Test
+ public void resolve_newerThanOldestSupportedTheme_shouldReturnSpecifiedTheme() {
+ ThemeResolver themeResolver =
+ new ThemeResolver.Builder()
+ .setOldestSupportedTheme(WizardManagerHelper.THEME_GLIF_V2)
+ .build();
+ assertThat(themeResolver.resolve("glif_v2")).isEqualTo(R.style.SuwThemeGlifV2_DayNight);
+ assertThat(themeResolver.resolve("glif_v2_light")).isEqualTo(R.style.SuwThemeGlifV2_DayNight);
+ assertThat(themeResolver.resolve("glif_v3")).isEqualTo(R.style.SuwThemeGlifV3_DayNight);
+ assertThat(themeResolver.resolve("glif_v3_light")).isEqualTo(R.style.SuwThemeGlifV3_DayNight);
+ }
+
+ @Test
+ public void resolve_olderThanOldestSupportedTheme_shouldReturnDefault() {
+ @StyleRes int defaultTheme = 12345;
+ ThemeResolver themeResolver =
+ new ThemeResolver.Builder()
+ .setDefaultTheme(defaultTheme)
+ .setOldestSupportedTheme(WizardManagerHelper.THEME_GLIF_V2)
+ .build();
+ assertThat(themeResolver.resolve("material")).isEqualTo(defaultTheme);
+ assertThat(themeResolver.resolve("material_light")).isEqualTo(defaultTheme);
+ assertThat(themeResolver.resolve("glif")).isEqualTo(defaultTheme);
+ assertThat(themeResolver.resolve("glif_light")).isEqualTo(defaultTheme);
+ }
+
+ @Test
+ public void resolve_intentTheme_shouldReturnCorrespondingTheme() {
+ @StyleRes int defaultTheme = 12345;
+ ThemeResolver themeResolver =
+ new ThemeResolver.Builder().setDefaultTheme(defaultTheme).setUseDayNight(false).build();
+ assertThat(
+ themeResolver.resolve(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "material")))
+ .isEqualTo(R.style.SuwThemeMaterial);
+ assertThat(
+ themeResolver.resolve(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "material_light")))
+ .isEqualTo(R.style.SuwThemeMaterial_Light);
+ assertThat(
+ themeResolver.resolve(new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif")))
+ .isEqualTo(R.style.SuwThemeGlif);
+ assertThat(
+ themeResolver.resolve(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_light")))
+ .isEqualTo(R.style.SuwThemeGlif_Light);
+ assertThat(
+ themeResolver.resolve(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v2")))
+ .isEqualTo(R.style.SuwThemeGlifV2);
+ assertThat(
+ themeResolver.resolve(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v2_light")))
+ .isEqualTo(R.style.SuwThemeGlifV2_Light);
+ assertThat(
+ themeResolver.resolve(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3")))
+ .isEqualTo(R.style.SuwThemeGlifV3);
+ assertThat(
+ themeResolver.resolve(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3_light")))
+ .isEqualTo(R.style.SuwThemeGlifV3_Light);
+ assertThat(
+ themeResolver.resolve(
+ new Intent().putExtra(WizardManagerHelper.EXTRA_THEME, "unknown_theme")))
+ .isEqualTo(defaultTheme);
+ }
+
+ @Test
+ public void resolve_suwIntent_shouldForceNonDayNightTheme() {
+ @StyleRes int defaultTheme = 12345;
+ ThemeResolver themeResolver =
+ new ThemeResolver.Builder().setDefaultTheme(defaultTheme).setUseDayNight(true).build();
+ Intent originalIntent = new Intent().putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "material")))
+ .isEqualTo(R.style.SuwThemeMaterial);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent)
+ .putExtra(WizardManagerHelper.EXTRA_THEME, "material_light")))
+ .isEqualTo(R.style.SuwThemeMaterial_Light);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "glif")))
+ .isEqualTo(R.style.SuwThemeGlif);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "glif_light")))
+ .isEqualTo(R.style.SuwThemeGlif_Light);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v2")))
+ .isEqualTo(R.style.SuwThemeGlifV2);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent)
+ .putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v2_light")))
+ .isEqualTo(R.style.SuwThemeGlifV2_Light);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent).putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3")))
+ .isEqualTo(R.style.SuwThemeGlifV3);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent)
+ .putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3_light")))
+ .isEqualTo(R.style.SuwThemeGlifV3_Light);
+ assertThat(
+ themeResolver.resolve(
+ new Intent(originalIntent)
+ .putExtra(WizardManagerHelper.EXTRA_THEME, "unknown_theme")))
+ .isEqualTo(defaultTheme);
+ }
+
+ @Test
+ public void applyTheme_glifV3_shouldSetActivityThemeToGlifV3() {
+ @StyleRes int defaultTheme = 12345;
+ ThemeResolver themeResolver =
+ new ThemeResolver.Builder().setUseDayNight(false).setDefaultTheme(defaultTheme).build();
+
+ Activity activity =
+ Robolectric.buildActivity(
+ Activity.class,
+ new Intent()
+ .putExtra(WizardManagerHelper.EXTRA_THEME, WizardManagerHelper.THEME_GLIF_V3))
+ .setup()
+ .get();
+
+ themeResolver.applyTheme(activity);
+
+ assertThat(shadowOf(activity).callGetThemeResId()).isEqualTo(R.style.SuwThemeGlifV3);
+ }
+
+ @Test
+ public void setDefault_shouldSetDefaultResolver() {
+ ThemeResolver themeResolver = new ThemeResolver.Builder().setUseDayNight(false).build();
+
+ ThemeResolver.setDefault(themeResolver);
+ assertThat(ThemeResolver.getDefault()).isSameAs(themeResolver);
+ }
+}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java b/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java
index 616ccdd..e302cab 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/util/WizardManagerHelperTest.java
@@ -16,10 +16,10 @@
package com.android.setupwizardlib.util;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.robolectric.RuntimeEnvironment.application;
+import static org.robolectric.Shadows.shadowOf;
import android.annotation.TargetApi;
import android.app.Activity;
@@ -29,299 +29,343 @@ import android.os.Bundle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
-
import androidx.annotation.StyleRes;
-
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;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
@Config(sdk = Config.NEWEST_SDK)
public class WizardManagerHelperTest {
- @Test
- public void testGetNextIntent() {
- final Intent intent = new Intent("test.intent.ACTION");
- intent.putExtra("scriptUri", "android-resource://test-script");
- intent.putExtra("actionId", "test_action_id");
- intent.putExtra("theme", "test_theme");
- intent.putExtra("ignoreExtra", "poof"); // extra is ignored because it's not known
-
- final Intent data = new Intent();
- data.putExtra("extraData", "shazam");
-
- final Intent nextIntent =
- WizardManagerHelper.getNextIntent(intent, Activity.RESULT_OK, data);
- assertEquals("Next intent action should be NEXT", "com.android.wizard.NEXT",
- nextIntent.getAction());
- assertEquals("Script URI should be the same as original intent",
- "android-resource://test-script", nextIntent.getStringExtra("scriptUri"));
- assertEquals("Action ID should be the same as original intent", "test_action_id",
- nextIntent.getStringExtra("actionId"));
- assertEquals("Theme extra should be the same as original intent", "test_theme",
- nextIntent.getStringExtra("theme"));
- assertFalse("ignoreExtra should not be in nextIntent", nextIntent.hasExtra("ignoreExtra"));
- assertEquals("Result code extra should be RESULT_OK", Activity.RESULT_OK,
- nextIntent.getIntExtra("com.android.setupwizard.ResultCode", 0));
- assertEquals("Extra data should surface as extra in nextIntent", "shazam",
- nextIntent.getStringExtra("extraData"));
- }
-
- @Test
- public void testIsSetupWizardTrue() {
- final Intent intent = new Intent();
- intent.putExtra("firstRun", true);
- assertTrue("Is setup wizard should be true",
- WizardManagerHelper.isSetupWizardIntent(intent));
- }
-
- @Test
- public void testIsDeferredSetupTrue() {
- final Intent intent = new Intent();
- intent.putExtra("deferredSetup", true);
- assertTrue("Is deferred setup wizard should be true",
- WizardManagerHelper.isDeferredSetupWizard(intent));
- }
-
- @Test
- public void testIsPreDeferredSetupTrue() {
- final Intent intent = new Intent();
- intent.putExtra("preDeferredSetup", true);
- assertTrue("Is pre-deferred setup wizard should be true",
- WizardManagerHelper.isPreDeferredSetupWizard(intent));
- }
-
- @Test
- public void testIsSetupWizardFalse() {
- final Intent intent = new Intent();
- intent.putExtra("firstRun", false);
- assertFalse("Is setup wizard should be true",
- WizardManagerHelper.isSetupWizardIntent(intent));
- }
-
- @Test
- public void isLightTheme_shouldReturnTrue_whenThemeIsLight() {
- List<String> lightThemes = Arrays.asList(
- "holo_light",
- "material_light",
- "glif_light",
- "glif_v2_light",
- "glif_v3_light"
- );
- ArrayList<String> unexpectedIntentThemes = new ArrayList<>();
- ArrayList<String> unexpectedStringThemes = new ArrayList<>();
- for (final String theme : lightThemes) {
- Intent intent = new Intent();
- intent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
- if (!WizardManagerHelper.isLightTheme(intent, false)) {
- unexpectedIntentThemes.add(theme);
- }
- if (!WizardManagerHelper.isLightTheme(theme, false)) {
- unexpectedStringThemes.add(theme);
- }
- }
- assertTrue("Intent themes " + unexpectedIntentThemes + " should be light",
- unexpectedIntentThemes.isEmpty());
- assertTrue("String themes " + unexpectedStringThemes + " should be light",
- unexpectedStringThemes.isEmpty());
- }
-
- @Test
- public void isLightTheme_shouldReturnFalse_whenThemeIsNotLight() {
- List<String> lightThemes = Arrays.asList(
- "holo",
- "material",
- "glif",
- "glif_v2",
- "glif_v3"
- );
- ArrayList<String> unexpectedIntentThemes = new ArrayList<>();
- ArrayList<String> unexpectedStringThemes = new ArrayList<>();
- for (final String theme : lightThemes) {
- Intent intent = new Intent();
- intent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
- if (WizardManagerHelper.isLightTheme(intent, true)) {
- unexpectedIntentThemes.add(theme);
- }
- if (WizardManagerHelper.isLightTheme(theme, true)) {
- unexpectedStringThemes.add(theme);
- }
- }
- assertTrue("Intent themes " + unexpectedIntentThemes + " should not be light",
- unexpectedIntentThemes.isEmpty());
- assertTrue("String themes " + unexpectedStringThemes + " should not be light",
- unexpectedStringThemes.isEmpty());
- }
-
- @Test
- public void testIsLightThemeDefault() {
- final Intent intent = new Intent();
- intent.putExtra("theme", "abracadabra");
- assertTrue("isLightTheme should return default value true",
- WizardManagerHelper.isLightTheme(intent, true));
- assertFalse("isLightTheme should return default value false",
- WizardManagerHelper.isLightTheme(intent, false));
- }
-
- @Test
- public void testIsLightThemeUnspecified() {
- final Intent intent = new Intent();
- assertTrue("isLightTheme should return default value true",
- WizardManagerHelper.isLightTheme(intent, true));
- assertFalse("isLightTheme should return default value false",
- WizardManagerHelper.isLightTheme(intent, false));
- }
-
- @Test
- public void testGetThemeResGlifV3Light() {
- assertEquals(R.style.SuwThemeGlifV3_Light,
- WizardManagerHelper.getThemeRes("glif_v3_light", 0));
- }
-
- @Test
- public void testGetThemeResGlifV3() {
- assertEquals(R.style.SuwThemeGlifV3,
- WizardManagerHelper.getThemeRes("glif_v3", 0));
+ @Test
+ public void testGetNextIntent() {
+ final Intent intent = new Intent("test.intent.ACTION");
+ intent.putExtra("scriptUri", "android-resource://test-script");
+ intent.putExtra("actionId", "test_action_id");
+ intent.putExtra("theme", "test_theme");
+ intent.putExtra("ignoreExtra", "poof"); // extra is ignored because it's not known
+
+ final Intent data = new Intent();
+ data.putExtra("extraData", "shazam");
+
+ final Intent nextIntent = WizardManagerHelper.getNextIntent(intent, Activity.RESULT_OK, data);
+ assertWithMessage("Next intent action should be NEXT")
+ .that(nextIntent.getAction())
+ .isEqualTo("com.android.wizard.NEXT");
+ assertWithMessage("Script URI should be the same as original intent")
+ .that(nextIntent.getStringExtra("scriptUri"))
+ .isEqualTo("android-resource://test-script");
+ assertWithMessage("Action ID should be the same as original intent")
+ .that(nextIntent.getStringExtra("actionId"))
+ .isEqualTo("test_action_id");
+ assertWithMessage("Theme extra should be the same as original intent")
+ .that(nextIntent.getStringExtra("theme"))
+ .isEqualTo("test_theme");
+ assertWithMessage("ignoreExtra should not be in nextIntent")
+ .that(nextIntent.hasExtra("ignoreExtra"))
+ .isFalse();
+ assertWithMessage("Result code extra should be RESULT_OK")
+ .that(nextIntent.getIntExtra("com.android.setupwizard.ResultCode", 0))
+ .isEqualTo(Activity.RESULT_OK);
+ assertWithMessage("Extra data should surface as extra in nextIntent")
+ .that(nextIntent.getStringExtra("extraData"))
+ .isEqualTo("shazam");
+ }
+
+ @Test
+ public void testIsSetupWizardTrue() {
+ final Intent intent = new Intent();
+ intent.putExtra("firstRun", true);
+ assertWithMessage("Is setup wizard should be true")
+ .that(WizardManagerHelper.isSetupWizardIntent(intent))
+ .isTrue();
+ }
+
+ @Test
+ public void testIsDeferredSetupTrue() {
+ final Intent intent = new Intent();
+ intent.putExtra("deferredSetup", true);
+ assertWithMessage("Is deferred setup wizard should be true")
+ .that(WizardManagerHelper.isDeferredSetupWizard(intent))
+ .isTrue();
+ }
+
+ @Test
+ public void testIsPreDeferredSetupTrue() {
+ final Intent intent = new Intent();
+ intent.putExtra("preDeferredSetup", true);
+ assertWithMessage("Is pre-deferred setup wizard should be true")
+ .that(WizardManagerHelper.isPreDeferredSetupWizard(intent))
+ .isTrue();
+ }
+
+ @Test
+ public void testIsSetupWizardFalse() {
+ final Intent intent = new Intent();
+ intent.putExtra("firstRun", false);
+ assertWithMessage("Is setup wizard should be true")
+ .that(WizardManagerHelper.isSetupWizardIntent(intent))
+ .isFalse();
+ }
+
+ @Test
+ public void isLightTheme_shouldReturnTrue_whenThemeIsLight() {
+ List<String> lightThemes =
+ Arrays.asList(
+ "holo_light", "material_light", "glif_light", "glif_v2_light", "glif_v3_light");
+ ArrayList<String> unexpectedIntentThemes = new ArrayList<>();
+ ArrayList<String> unexpectedStringThemes = new ArrayList<>();
+ for (final String theme : lightThemes) {
+ Intent intent = new Intent();
+ intent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
+ if (!WizardManagerHelper.isLightTheme(intent, false)) {
+ unexpectedIntentThemes.add(theme);
+ }
+ if (!WizardManagerHelper.isLightTheme(theme, false)) {
+ unexpectedStringThemes.add(theme);
+ }
}
-
- @Test
- public void testGetThemeResGlifV2Light() {
- assertEquals(R.style.SuwThemeGlifV2_Light,
- WizardManagerHelper.getThemeRes("glif_v2_light", 0));
- }
-
- @Test
- public void testGetThemeResGlifV2() {
- assertEquals(R.style.SuwThemeGlifV2,
- WizardManagerHelper.getThemeRes("glif_v2", 0));
- }
-
- @Test
- public void testGetThemeResGlifLight() {
- assertEquals(R.style.SuwThemeGlif_Light,
- WizardManagerHelper.getThemeRes("glif_light", 0));
- }
-
- @Test
- public void testGetThemeResGlif() {
- assertEquals(R.style.SuwThemeGlif,
- WizardManagerHelper.getThemeRes("glif", 0));
- }
-
- @Test
- public void testGetThemeResMaterialLight() {
- assertEquals(R.style.SuwThemeMaterial_Light,
- WizardManagerHelper.getThemeRes("material_light", 0));
- }
-
- @Test
- public void testGetThemeResMaterial() {
- assertEquals(R.style.SuwThemeMaterial,
- WizardManagerHelper.getThemeRes("material", 0));
- }
-
- @Test
- public void testGetThemeResDefault() {
- @StyleRes int def = 123;
- assertEquals(def, WizardManagerHelper.getThemeRes("abracadabra", def));
- }
-
- @Test
- public void testGetThemeResNull() {
- @StyleRes int def = 123;
- assertEquals(def, WizardManagerHelper.getThemeRes((String) null, def));
- }
-
- @Test
- public void testGetThemeResFromIntent() {
- Intent intent = new Intent();
- intent.putExtra(WizardManagerHelper.EXTRA_THEME, "material");
- assertEquals(R.style.SuwThemeMaterial, WizardManagerHelper.getThemeRes(intent, 0));
- }
-
- @Test
- public void testCopyWizardManagerIntent() {
- Bundle wizardBundle = new Bundle();
- wizardBundle.putString("foo", "bar");
- Intent originalIntent = new Intent()
- .putExtra(WizardManagerHelper.EXTRA_THEME, "test_theme")
- .putExtra(WizardManagerHelper.EXTRA_WIZARD_BUNDLE, wizardBundle)
- .putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true)
- .putExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, true)
- .putExtra(WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP, true)
- // Script URI and Action ID are kept for backwards compatibility
- .putExtra(WizardManagerHelper.EXTRA_SCRIPT_URI, "test_script_uri")
- .putExtra(WizardManagerHelper.EXTRA_ACTION_ID, "test_action_id");
-
- Intent intent = new Intent("test.intent.action");
- WizardManagerHelper.copyWizardManagerExtras(originalIntent, intent);
-
- assertEquals("Intent action should be kept", "test.intent.action", intent.getAction());
- assertEquals("EXTRA_THEME should be copied",
- "test_theme", intent.getStringExtra(WizardManagerHelper.EXTRA_THEME));
- Bundle copiedWizardBundle =
- intent.getParcelableExtra(WizardManagerHelper.EXTRA_WIZARD_BUNDLE);
- assertEquals("Wizard bundle should be copied", "bar", copiedWizardBundle.getString("foo"));
-
- assertTrue("EXTRA_IS_FIRST_RUN should be copied",
- intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, false));
- assertTrue("EXTRA_IS_DEFERRED_SETUP should be copied",
- intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, false));
- assertTrue("EXTRA_IS_PRE_DEFERRED_SETUP should be copied",
- intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP, false));
-
- // Script URI and Action ID are replaced by Wizard Bundle in M, but are kept for backwards
- // compatibility
- assertEquals("EXTRA_SCRIPT_URI should be copied",
- "test_script_uri", intent.getStringExtra(WizardManagerHelper.EXTRA_SCRIPT_URI));
- assertEquals("EXTRA_ACTION_ID should be copied",
- "test_action_id", intent.getStringExtra(WizardManagerHelper.EXTRA_ACTION_ID));
- }
-
- @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
- @Test
- public void testIsUserSetupComplete() {
- Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
- Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 1);
- assertTrue(WizardManagerHelper.isUserSetupComplete(application));
-
- Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 0);
- assertFalse(WizardManagerHelper.isUserSetupComplete(application));
- }
-
- @Test
- @Config(sdk = VERSION_CODES.JELLY_BEAN)
- public void testIsUserSetupCompleteCompat() {
- Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1);
- assertTrue(WizardManagerHelper.isUserSetupComplete(application));
-
- Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0);
- assertFalse(WizardManagerHelper.isUserSetupComplete(application));
- }
-
- @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
- @Test
- public void testIsDeviceProvisioned() {
- Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
- assertTrue(WizardManagerHelper.isDeviceProvisioned(application));
- Settings.Secure.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 0);
- assertFalse(WizardManagerHelper.isDeviceProvisioned(application));
- }
-
- @Test
- @Config(sdk = VERSION_CODES.JELLY_BEAN)
- public void testIsDeviceProvisionedCompat() {
- Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1);
- assertTrue(WizardManagerHelper.isDeviceProvisioned(application));
- Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0);
- assertFalse(WizardManagerHelper.isDeviceProvisioned(application));
+ assertWithMessage("Intent themes " + unexpectedIntentThemes + " should be light")
+ .that(unexpectedIntentThemes.isEmpty())
+ .isTrue();
+ assertWithMessage("String themes " + unexpectedStringThemes + " should be light")
+ .that(unexpectedStringThemes.isEmpty())
+ .isTrue();
+ }
+
+ @Test
+ public void isLightTheme_shouldReturnFalse_whenThemeIsNotLight() {
+ List<String> lightThemes = Arrays.asList("holo", "material", "glif", "glif_v2", "glif_v3");
+ ArrayList<String> unexpectedIntentThemes = new ArrayList<>();
+ ArrayList<String> unexpectedStringThemes = new ArrayList<>();
+ for (final String theme : lightThemes) {
+ Intent intent = new Intent();
+ intent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
+ if (WizardManagerHelper.isLightTheme(intent, true)) {
+ unexpectedIntentThemes.add(theme);
+ }
+ if (WizardManagerHelper.isLightTheme(theme, true)) {
+ unexpectedStringThemes.add(theme);
+ }
}
+ assertWithMessage("Intent themes " + unexpectedIntentThemes + " should not be light")
+ .that(unexpectedIntentThemes.isEmpty())
+ .isTrue();
+ assertWithMessage("String themes " + unexpectedStringThemes + " should not be light")
+ .that(unexpectedStringThemes.isEmpty())
+ .isTrue();
+ }
+
+ @Test
+ public void getThemeRes_whenOldestSupportedThemeTakeEffect_shouldReturnDefault() {
+ Intent intent = new Intent();
+ intent.putExtra(WizardManagerHelper.EXTRA_THEME, "material");
+ assertThat(WizardManagerHelper.getThemeRes(intent, 0, WizardManagerHelper.THEME_GLIF_V2))
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void getThemeRes_whenOldestSupportedThemeNotTakeEffect_shouldReturnCurrent() {
+ Intent intent = new Intent();
+ intent.putExtra(WizardManagerHelper.EXTRA_THEME, "glif_v3");
+ assertThat(WizardManagerHelper.getThemeRes(intent, 0, WizardManagerHelper.THEME_GLIF_V2))
+ .isEqualTo(R.style.SuwThemeGlifV3);
+ }
+
+ @Test
+ public void testIsLightThemeDefault() {
+ final Intent intent = new Intent();
+ intent.putExtra("theme", "abracadabra");
+ assertWithMessage("isLightTheme should return default value true")
+ .that(WizardManagerHelper.isLightTheme(intent, true))
+ .isTrue();
+ assertWithMessage("isLightTheme should return default value false")
+ .that(WizardManagerHelper.isLightTheme(intent, false))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsLightThemeUnspecified() {
+ final Intent intent = new Intent();
+ assertWithMessage("isLightTheme should return default value true")
+ .that(WizardManagerHelper.isLightTheme(intent, true))
+ .isTrue();
+ assertWithMessage("isLightTheme should return default value false")
+ .that(WizardManagerHelper.isLightTheme(intent, false))
+ .isFalse();
+ }
+
+ @Test
+ public void testGetThemeResGlifV3Light() {
+ assertThat(WizardManagerHelper.getThemeRes("glif_v3_light", 0))
+ .isEqualTo(R.style.SuwThemeGlifV3_Light);
+ }
+
+ @Test
+ public void testGetThemeResGlifV3() {
+ assertThat(WizardManagerHelper.getThemeRes("glif_v3", 0)).isEqualTo(R.style.SuwThemeGlifV3);
+ }
+
+ @Test
+ public void testGetThemeResGlifV2Light() {
+ assertThat(WizardManagerHelper.getThemeRes("glif_v2_light", 0))
+ .isEqualTo(R.style.SuwThemeGlifV2_Light);
+ }
+
+ @Test
+ public void testGetThemeResGlifV2() {
+ assertThat(WizardManagerHelper.getThemeRes("glif_v2", 0)).isEqualTo(R.style.SuwThemeGlifV2);
+ }
+
+ @Test
+ public void testGetThemeResGlifLight() {
+ assertThat(WizardManagerHelper.getThemeRes("glif_light", 0))
+ .isEqualTo(R.style.SuwThemeGlif_Light);
+ }
+
+ @Test
+ public void testGetThemeResGlif() {
+ assertThat(WizardManagerHelper.getThemeRes("glif", 0)).isEqualTo(R.style.SuwThemeGlif);
+ }
+
+ @Test
+ public void testGetThemeResMaterialLight() {
+ assertThat(WizardManagerHelper.getThemeRes("material_light", 0))
+ .isEqualTo(R.style.SuwThemeMaterial_Light);
+ }
+
+ @Test
+ public void testGetThemeResMaterial() {
+ assertThat(WizardManagerHelper.getThemeRes("material", 0)).isEqualTo(R.style.SuwThemeMaterial);
+ }
+
+ @Test
+ public void testGetThemeResDefault() {
+ @StyleRes int def = 123;
+ assertThat(WizardManagerHelper.getThemeRes("abracadabra", def)).isEqualTo(def);
+ }
+
+ @Test
+ public void testGetThemeResNull() {
+ @StyleRes int def = 123;
+ assertThat(WizardManagerHelper.getThemeRes((String) null, def)).isEqualTo(def);
+ }
+
+ @Test
+ public void testGetThemeResFromIntent() {
+ Intent intent = new Intent();
+ intent.putExtra(WizardManagerHelper.EXTRA_THEME, "material");
+ assertThat(WizardManagerHelper.getThemeRes(intent, 0)).isEqualTo(R.style.SuwThemeMaterial);
+ }
+
+ @Test
+ public void testCopyWizardManagerIntent() {
+ Bundle wizardBundle = new Bundle();
+ wizardBundle.putString("foo", "bar");
+ Intent originalIntent =
+ new Intent()
+ .putExtra(WizardManagerHelper.EXTRA_THEME, "test_theme")
+ .putExtra(WizardManagerHelper.EXTRA_WIZARD_BUNDLE, wizardBundle)
+ .putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true)
+ .putExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, true)
+ .putExtra(WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP, true)
+ // Script URI and Action ID are kept for backwards compatibility
+ .putExtra(WizardManagerHelper.EXTRA_SCRIPT_URI, "test_script_uri")
+ .putExtra(WizardManagerHelper.EXTRA_ACTION_ID, "test_action_id");
+
+ Intent intent = new Intent("test.intent.action");
+ WizardManagerHelper.copyWizardManagerExtras(originalIntent, intent);
+
+ assertWithMessage("Intent action should be kept")
+ .that(intent.getAction())
+ .isEqualTo("test.intent.action");
+ assertWithMessage("EXTRA_THEME should be copied")
+ .that(intent.getStringExtra(WizardManagerHelper.EXTRA_THEME))
+ .isEqualTo("test_theme");
+ Bundle copiedWizardBundle = intent.getParcelableExtra(WizardManagerHelper.EXTRA_WIZARD_BUNDLE);
+ assertWithMessage("Wizard bundle should be copied")
+ .that(copiedWizardBundle.getString("foo"))
+ .isEqualTo("bar");
+
+ assertWithMessage("EXTRA_IS_FIRST_RUN should be copied")
+ .that(intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, false))
+ .isTrue();
+ assertWithMessage("EXTRA_IS_DEFERRED_SETUP should be copied")
+ .that(intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, false))
+ .isTrue();
+ assertWithMessage("EXTRA_IS_PRE_DEFERRED_SETUP should be copied")
+ .that(intent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP, false))
+ .isTrue();
+
+ // Script URI and Action ID are replaced by Wizard Bundle in M, but are kept for backwards
+ // compatibility
+ assertWithMessage("EXTRA_SCRIPT_URI should be copied")
+ .that(intent.getStringExtra(WizardManagerHelper.EXTRA_SCRIPT_URI))
+ .isEqualTo("test_script_uri");
+ assertWithMessage("EXTRA_ACTION_ID should be copied")
+ .that(intent.getStringExtra(WizardManagerHelper.EXTRA_ACTION_ID))
+ .isEqualTo("test_action_id");
+ }
+
+ @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
+ @Test
+ public void testIsUserSetupComplete() {
+ Settings.Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
+ Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 1);
+ assertThat(WizardManagerHelper.isUserSetupComplete(application)).isTrue();
+
+ Settings.Secure.putInt(application.getContentResolver(), "user_setup_complete", 0);
+ assertThat(WizardManagerHelper.isUserSetupComplete(application)).isFalse();
+ }
+
+ @Test
+ @Config(sdk = VERSION_CODES.JELLY_BEAN)
+ public void testIsUserSetupCompleteCompat() {
+ Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1);
+ assertThat(WizardManagerHelper.isUserSetupComplete(application)).isTrue();
+
+ Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0);
+ assertThat(WizardManagerHelper.isUserSetupComplete(application)).isFalse();
+ }
+
+ @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
+ @Test
+ public void testIsDeviceProvisioned() {
+ Settings.Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
+ assertThat(WizardManagerHelper.isDeviceProvisioned(application)).isTrue();
+ Settings.Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 0);
+ assertThat(WizardManagerHelper.isDeviceProvisioned(application)).isFalse();
+ }
+
+ @Test
+ @Config(sdk = VERSION_CODES.JELLY_BEAN)
+ public void testIsDeviceProvisionedCompat() {
+ Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 1);
+ assertThat(WizardManagerHelper.isDeviceProvisioned(application)).isTrue();
+ Settings.Secure.putInt(application.getContentResolver(), Secure.DEVICE_PROVISIONED, 0);
+ assertThat(WizardManagerHelper.isDeviceProvisioned(application)).isFalse();
+ }
+
+ @Test
+ public void applyTheme_glifDayNight_shouldApplyThemeToActivity() {
+ Activity activity =
+ Robolectric.buildActivity(
+ Activity.class,
+ new Intent()
+ .putExtra(
+ WizardManagerHelper.EXTRA_THEME, WizardManagerHelper.THEME_GLIF_LIGHT))
+ .setup()
+ .get();
+
+ WizardManagerHelper.applyTheme(activity);
+
+ assertThat(shadowOf(activity).callGetThemeResId()).isEqualTo(R.style.SuwThemeGlif_DayNight);
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java b/library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java
index ae4f3d1..001f1da 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/view/FillContentLayoutTest.java
@@ -16,72 +16,73 @@
package com.android.setupwizardlib.view;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.RuntimeEnvironment.application;
import android.view.View;
import android.view.View.MeasureSpec;
-
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-@RunWith(SuwLibRobolectricTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
public class FillContentLayoutTest {
- @Test
- public void testMeasureMinSize() {
- FillContentLayout layout = new FillContentLayout(
- application,
- Robolectric.buildAttributeSet()
- .addAttribute(android.R.attr.minWidth, "123dp")
- .addAttribute(android.R.attr.minHeight, "123dp")
- .build());
- layout.measure(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ @Test
+ public void testMeasureMinSize() {
+ FillContentLayout layout =
+ new FillContentLayout(
+ application,
+ Robolectric.buildAttributeSet()
+ .addAttribute(android.R.attr.minWidth, "123dp")
+ .addAttribute(android.R.attr.minHeight, "123dp")
+ .build());
+ layout.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- assertEquals(123, layout.getMeasuredWidth());
- assertEquals(123, layout.getMeasuredHeight());
- }
+ assertThat(layout.getMeasuredWidth()).isEqualTo(123);
+ assertThat(layout.getMeasuredHeight()).isEqualTo(123);
+ }
- @Test
- public void testMeasureChildIsSmallerThanMaxSize() {
- View child = new View(application);
- FillContentLayout layout = new FillContentLayout(
- application,
- Robolectric.buildAttributeSet()
- .addAttribute(android.R.attr.maxWidth, "123dp")
- .addAttribute(android.R.attr.maxHeight, "123dp")
- .build());
- layout.addView(child);
- layout.measure(
- MeasureSpec.makeMeasureSpec(300, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(300, MeasureSpec.EXACTLY));
+ @Test
+ public void testMeasureChildIsSmallerThanMaxSize() {
+ View child = new View(application);
+ FillContentLayout layout =
+ new FillContentLayout(
+ application,
+ Robolectric.buildAttributeSet()
+ .addAttribute(android.R.attr.maxWidth, "123dp")
+ .addAttribute(android.R.attr.maxHeight, "123dp")
+ .build());
+ layout.addView(child);
+ layout.measure(
+ MeasureSpec.makeMeasureSpec(300, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(300, MeasureSpec.EXACTLY));
- assertEquals(123, child.getMeasuredWidth());
- assertEquals(123, child.getMeasuredHeight());
- }
+ assertThat(child.getMeasuredWidth()).isEqualTo(123);
+ assertThat(child.getMeasuredHeight()).isEqualTo(123);
+ }
- @Test
- public void testMeasureChildIsSmallerThanParent() {
- View child = new View(application);
- FillContentLayout layout = new FillContentLayout(
- application,
- Robolectric.buildAttributeSet()
- .addAttribute(android.R.attr.maxWidth, "123dp")
- .addAttribute(android.R.attr.maxHeight, "123dp")
- .build());
- layout.addView(child);
- layout.measure(
- MeasureSpec.makeMeasureSpec(88, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(88, MeasureSpec.EXACTLY));
+ @Test
+ public void testMeasureChildIsSmallerThanParent() {
+ View child = new View(application);
+ FillContentLayout layout =
+ new FillContentLayout(
+ application,
+ Robolectric.buildAttributeSet()
+ .addAttribute(android.R.attr.maxWidth, "123dp")
+ .addAttribute(android.R.attr.maxHeight, "123dp")
+ .build());
+ layout.addView(child);
+ layout.measure(
+ MeasureSpec.makeMeasureSpec(88, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(88, MeasureSpec.EXACTLY));
- assertEquals(88, child.getMeasuredWidth());
- assertEquals(88, child.getMeasuredHeight());
- }
+ assertThat(child.getMeasuredWidth()).isEqualTo(88);
+ assertThat(child.getMeasuredHeight()).isEqualTo(88);
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java b/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java
index 0e0e99c..e980563 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/view/IllustrationVideoViewTest.java
@@ -17,204 +17,223 @@
package com.android.setupwizardlib.view;
import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
-import android.annotation.TargetApi;
-import android.content.Context;
+import android.app.Activity;
import android.graphics.SurfaceTexture;
-import android.media.MediaPlayer;
-import android.os.Build.VERSION_CODES;
-import android.view.Surface;
-import android.view.View;
-
+import android.net.Uri;
import androidx.annotation.RawRes;
-
+import android.view.View;
import com.android.setupwizardlib.R;
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
-import com.android.setupwizardlib.shadow.ShadowLog;
-import com.android.setupwizardlib.shadow.ShadowLog.TerribleFailure;
-import com.android.setupwizardlib.view.IllustrationVideoViewTest.ShadowMockMediaPlayer;
-import com.android.setupwizardlib.view.IllustrationVideoViewTest.ShadowSurface;
-
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.RealObject;
-import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowMediaPlayer;
+import org.robolectric.shadows.ShadowMediaPlayer.InvalidStateBehavior;
+import org.robolectric.shadows.ShadowMediaPlayer.MediaInfo;
+import org.robolectric.shadows.util.DataSource;
import org.robolectric.util.ReflectionHelpers;
+import org.robolectric.util.ReflectionHelpers.ClassParameter;
-@RunWith(SuwLibRobolectricTestRunner.class)
-@Config(
- sdk = Config.NEWEST_SDK,
- shadows = {
- ShadowLog.class,
- ShadowMockMediaPlayer.class,
- ShadowSurface.class
- })
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = Config.NEWEST_SDK)
public class IllustrationVideoViewTest {
- @Mock
- private SurfaceTexture mSurfaceTexture;
-
- private IllustrationVideoView mView;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @After
- public void tearDown() {
- ShadowMockMediaPlayer.reset();
- }
-
- @Test
- public void nullMediaPlayer_shouldThrowWtf() {
- ShadowMockMediaPlayer.sMediaPlayer = null;
- try {
- createDefaultView();
- fail("WTF should be thrown for null media player");
- } catch (TerribleFailure e) {
- // pass
- }
- }
-
- @Test
- public void onVisibilityChanged_notVisible_shouldRelease() {
- createDefaultView();
- mView.onWindowVisibilityChanged(View.GONE);
-
- verify(ShadowMockMediaPlayer.sMediaPlayer).release();
- assertThat(mView.mSurface).isNull();
- assertThat(mView.mMediaPlayer).isNull();
- }
-
- @Test
- public void onVisibilityChanged_visible_shouldPlay() {
- createDefaultView();
-
- mView.onWindowVisibilityChanged(View.GONE);
- assertThat(mView.mSurface).isNull();
- assertThat(mView.mMediaPlayer).isNull();
-
- mView.onWindowVisibilityChanged(View.VISIBLE);
-
- assertThat(mView.mSurface).isNotNull();
- assertThat(mView.mMediaPlayer).isNotNull();
- }
-
- @Test
- public void testPausedWhenWindowFocusLost() {
- createDefaultView();
- mView.start();
-
- assertNotNull(mView.mMediaPlayer);
- assertNotNull(mView.mSurface);
-
- mView.onWindowFocusChanged(false);
- verify(ShadowMockMediaPlayer.getMock()).pause();
- }
-
- @Test
- public void testStartedWhenWindowFocusRegained() {
- testPausedWhenWindowFocusLost();
-
- // Clear verifications for calls in the other test
- reset(ShadowMockMediaPlayer.getMock());
-
- mView.onWindowFocusChanged(true);
- verify(ShadowMockMediaPlayer.getMock()).start();
- }
-
- @Test
- public void testSurfaceReleasedWhenTextureDestroyed() {
- createDefaultView();
- mView.start();
-
- assertNotNull(mView.mMediaPlayer);
- assertNotNull(mView.mSurface);
-
- mView.onSurfaceTextureDestroyed(mSurfaceTexture);
- verify(ShadowMockMediaPlayer.getMock()).release();
- }
-
- @Test
- public void testXmlSetVideoResId() {
- createDefaultView();
- assertEquals(android.R.color.white, ShadowMockMediaPlayer.sResId);
- }
-
- @Test
- public void testSetVideoResId() {
- createDefaultView();
-
- @RawRes int black = android.R.color.black;
- mView.setVideoResource(black);
-
- assertEquals(android.R.color.black, ShadowMockMediaPlayer.sResId);
- }
-
- private void createDefaultView() {
- mView = new IllustrationVideoView(
- application,
- Robolectric.buildAttributeSet()
- // Any resource attribute should work, since the media player is mocked
- .addAttribute(R.attr.suwVideo, "@android:color/white")
- .build());
- mView.setSurfaceTexture(mock(SurfaceTexture.class));
- mView.onSurfaceTextureAvailable(mSurfaceTexture, 500, 500);
- }
-
- @Implements(MediaPlayer.class)
- public static class ShadowMockMediaPlayer extends ShadowMediaPlayer {
-
- private static MediaPlayer sMediaPlayer = mock(MediaPlayer.class);
- private static int sResId;
-
- public static void reset() {
- sMediaPlayer = mock(MediaPlayer.class);
- sResId = 0;
- }
-
- @Implementation
- public static MediaPlayer create(Context context, int resId) {
- sResId = resId;
- return sMediaPlayer;
- }
-
- public static MediaPlayer getMock() {
- return sMediaPlayer;
- }
- }
-
- @Implements(Surface.class)
- @TargetApi(VERSION_CODES.HONEYCOMB)
- public static class ShadowSurface extends org.robolectric.shadows.ShadowSurface {
-
- @RealObject
- private Surface mRealSurface;
-
- public void __constructor__(SurfaceTexture surfaceTexture) {
- // Call the constructor on the real object, so that critical fields such as mLock is
- // initialized properly.
- Shadow.invokeConstructor(Surface.class, mRealSurface,
- ReflectionHelpers.ClassParameter.from(SurfaceTexture.class, surfaceTexture));
- super.__constructor__(surfaceTexture);
- }
- }
+ @Mock private SurfaceTexture surfaceTexture;
+
+ private IllustrationVideoView view;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowMediaPlayer.addMediaInfo(
+ DataSource.toDataSource(
+ "android.resource://" + application.getPackageName() + "/" + android.R.color.white),
+ new ShadowMediaPlayer.MediaInfo(100, 10));
+ ShadowMediaPlayer.addMediaInfo(
+ DataSource.toDataSource(
+ "android.resource://" + application.getPackageName() + "/" + android.R.color.black),
+ new ShadowMediaPlayer.MediaInfo(100, 10));
+ }
+
+ @Test
+ public void testPausedWhenWindowFocusLost() {
+ createDefaultView();
+ Robolectric.flushForegroundThreadScheduler();
+ view.start();
+
+ assertThat(view.mMediaPlayer).isNotNull();
+ assertThat(view.surface).isNotNull();
+
+ view.onWindowFocusChanged(false);
+ assertThat(getShadowMediaPlayer().getState()).isEqualTo(ShadowMediaPlayer.State.PAUSED);
+ }
+
+ @Test
+ public void testStartedWhenWindowFocusRegained() {
+ testPausedWhenWindowFocusLost();
+ Robolectric.flushForegroundThreadScheduler();
+
+ view.onWindowFocusChanged(true);
+ assertThat(getShadowMediaPlayer().getState()).isEqualTo(ShadowMediaPlayer.State.STARTED);
+ }
+
+ @Test
+ public void testSurfaceReleasedWhenTextureDestroyed() {
+ createDefaultView();
+ view.start();
+
+ assertThat(view.mMediaPlayer).isNotNull();
+ assertThat(view.surface).isNotNull();
+
+ // MediaPlayer is set to null after destroy. Retrieve it first before we call destroy.
+ ShadowMediaPlayer shadowMediaPlayer = getShadowMediaPlayer();
+ view.onSurfaceTextureDestroyed(surfaceTexture);
+ assertThat(shadowMediaPlayer.getState()).isEqualTo(ShadowMediaPlayer.State.END);
+ }
+
+ @Test
+ public void testXmlSetVideoResId() {
+ createDefaultView();
+ assertThat(getShadowMediaPlayer().getSourceUri().toString())
+ .isEqualTo("android.resource://com.android.setupwizardlib/" + android.R.color.white);
+ }
+
+ @Test
+ public void testSetVideoResId() {
+ createDefaultView();
+
+ @RawRes int black = android.R.color.black;
+ view.setVideoResource(black);
+
+ assertThat(getShadowMediaPlayer().getSourceUri().toString())
+ .isEqualTo("android.resource://com.android.setupwizardlib/" + android.R.color.black);
+ }
+
+ @Test
+ public void prepareVideo_shouldSetAspectRatio() {
+ createDefaultView();
+
+ ReflectionHelpers.setField(getShadowMediaPlayer(), "videoWidth", 720);
+ ReflectionHelpers.setField(getShadowMediaPlayer(), "videoHeight", 1280);
+
+ Robolectric.flushForegroundThreadScheduler();
+ view.start();
+
+ view.measure(
+ View.MeasureSpec.makeMeasureSpec(720, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(720, View.MeasureSpec.EXACTLY));
+
+ final float aspectRatio = (float) view.getMeasuredHeight() / view.getMeasuredWidth();
+ assertThat(aspectRatio).isWithin(0.001f).of(1280f / 720f);
+ }
+
+ @Test
+ public void prepareVideo_zeroHeight_shouldSetAspectRatioToZero() {
+ createDefaultView();
+
+ ReflectionHelpers.setField(getShadowMediaPlayer(), "videoWidth", 720);
+ ReflectionHelpers.setField(getShadowMediaPlayer(), "videoHeight", 0);
+
+ Robolectric.flushForegroundThreadScheduler();
+ view.start();
+
+ final float aspectRatio = (float) view.getHeight() / view.getWidth();
+ assertThat(aspectRatio).isEqualTo(0.0f);
+ }
+
+ @Test
+ public void setVideoResId_resetDiffVideoResFromDiffPackage_videoResShouldBeSet() {
+ // VideoRes default set as android.R.color.white with
+ // default package(com.android.setupwizardlib)
+ createDefaultView();
+
+ // reset different videoRes from different package
+ String newPackageName = "com.android.fakepackage";
+ @RawRes int black = android.R.color.black;
+ addMediaInfo(black, newPackageName);
+ view.setVideoResource(black, newPackageName);
+
+ // should be reset to black with the new package
+ assertThat(getShadowMediaPlayer().getSourceUri().toString())
+ .isEqualTo("android.resource://" + newPackageName + "/" + android.R.color.black);
+ }
+
+ @Test
+ public void setVideoResId_resetDiffVideoResFromSamePackage_videoResShouldBeSet() {
+ // VideoRes default set as android.R.color.white with
+ // default package(com.android.setupwizardlib)
+ createDefaultView();
+
+ // reset different videoRes from the same package(default package)
+ String defaultPackageName = "com.android.setupwizardlib";
+ @RawRes int black = android.R.color.black;
+ addMediaInfo(black, defaultPackageName);
+ view.setVideoResource(black, defaultPackageName);
+
+ // should be reset to black with the same package(default package)
+ assertThat(getShadowMediaPlayer().getSourceUri().toString())
+ .isEqualTo("android.resource://" + defaultPackageName + "/" + android.R.color.black);
+ }
+
+ @Test
+ public void setVideoResId_resetSameVideoResFromDifferentPackage_videoResShouldBeSet() {
+ // VideoRes default set as android.R.color.white with
+ // default package(com.android.setupwizardlib)
+ createDefaultView();
+
+ // reset same videoRes from different package
+ @RawRes int white = android.R.color.white;
+ String newPackageName = "com.android.fakepackage";
+ addMediaInfo(white, newPackageName);
+ view.setVideoResource(white, newPackageName);
+
+ // should be white with the new package
+ assertThat(getShadowMediaPlayer().getSourceUri().toString())
+ .isEqualTo("android.resource://" + newPackageName + "/" + android.R.color.white);
+ }
+
+ private ShadowMediaPlayer getShadowMediaPlayer() {
+ return Shadows.shadowOf(view.mMediaPlayer);
+ }
+
+ private void createDefaultView() {
+ view =
+ new IllustrationVideoView(
+ application,
+ Robolectric.buildAttributeSet()
+ // Any resource attribute should work, since the data source is fake
+ .addAttribute(R.attr.suwVideo, "@android:color/white")
+ .build());
+
+ Activity activity = Robolectric.setupActivity(Activity.class);
+ activity.setContentView(view);
+ setWindowVisible();
+
+ view.setSurfaceTexture(mock(SurfaceTexture.class));
+ view.onSurfaceTextureAvailable(surfaceTexture, 500, 500);
+ getShadowMediaPlayer().setInvalidStateBehavior(InvalidStateBehavior.EMULATE);
+ }
+
+ private void setWindowVisible() {
+ Object viewRootImpl = ReflectionHelpers.callInstanceMethod(view, "getViewRootImpl");
+ ReflectionHelpers.callInstanceMethod(
+ viewRootImpl, "handleAppVisibility", ClassParameter.from(boolean.class, true));
+ assertThat(view.isAttachedToWindow()).isTrue();
+ assertThat(view.getWindowVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ private void addMediaInfo(@RawRes int res, String packageName) {
+ ShadowMediaPlayer.addMediaInfo(
+ DataSource.toDataSource(
+ application, Uri.parse("android.resource://" + packageName + "/" + res), null),
+ new MediaInfo(5000, 1));
+ }
}
diff --git a/library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java b/library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java
index f77de68..477c42a 100644
--- a/library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java
+++ b/library/test/robotest/src/com/android/setupwizardlib/view/RichTextViewTest.java
@@ -17,15 +17,10 @@
package com.android.setupwizardlib.view;
import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
@@ -39,201 +34,196 @@ import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.TextAppearanceSpan;
import android.view.MotionEvent;
-
-import com.android.setupwizardlib.robolectric.SuwLibRobolectricTestRunner;
import com.android.setupwizardlib.span.LinkSpan;
import com.android.setupwizardlib.span.LinkSpan.OnLinkClickListener;
import com.android.setupwizardlib.view.TouchableMovementMethod.TouchableLinkMovementMethod;
-
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-import java.util.Arrays;
-
-@RunWith(SuwLibRobolectricTestRunner.class)
-@Config(sdk = { Config.OLDEST_SDK, Config.NEWEST_SDK })
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Config.OLDEST_SDK, Config.NEWEST_SDK})
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(application);
- textView.setText(ssb);
-
- final CharSequence text = textView.getText();
- assertTrue("Text should be spanned", text instanceof Spanned);
-
- assertThat(textView.getMovementMethod()).isInstanceOf(TouchableLinkMovementMethod.class);
-
- 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 testOnLinkClickListener() {
- Annotation link = new Annotation("link", "foobar");
- SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
- ssb.setSpan(link, 1, 2, 0 /* flags */);
+ @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(application);
+ textView.setText(ssb);
+
+ final CharSequence text = textView.getText();
+ assertThat(text).isInstanceOf(Spanned.class);
+
+ assertThat(textView.getMovementMethod()).isInstanceOf(TouchableLinkMovementMethod.class);
- RichTextView textView = new RichTextView(application);
- textView.setText(ssb);
+ Object[] spans = ((Spanned) text).getSpans(0, text.length(), Annotation.class);
+ assertThat(spans).isEmpty();
- OnLinkClickListener listener = mock(OnLinkClickListener.class);
- textView.setOnLinkClickListener(listener);
+ spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class);
+ assertThat(spans).hasLength(1);
+ assertThat(spans[0]).isInstanceOf(LinkSpan.class);
+ assertWithMessage("The LinkSpan should have id \"foobar\"")
+ .that(((LinkSpan) spans[0]).getId())
+ .isEqualTo("foobar");
+ }
+
+ @Test
+ public void testOnLinkClickListener() {
+ Annotation link = new Annotation("link", "foobar");
+ SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
+ ssb.setSpan(link, 1, 2, 0 /* flags */);
+
+ RichTextView textView = new RichTextView(application);
+ textView.setText(ssb);
- assertSame(listener, textView.getOnLinkClickListener());
-
- CharSequence text = textView.getText();
- LinkSpan[] spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class);
- spans[0].onClick(textView);
-
- verify(listener).onLinkClick(eq(spans[0]));
+ OnLinkClickListener listener = mock(OnLinkClickListener.class);
+ textView.setOnLinkClickListener(listener);
+
+ assertThat(textView.getOnLinkClickListener()).isSameAs(listener);
+
+ CharSequence text = textView.getText();
+ LinkSpan[] spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class);
+ spans[0].onClick(textView);
+
+ verify(listener).onLinkClick(eq(spans[0]));
+ }
+
+ @Test
+ public void testLegacyContextOnClickListener() {
+ // Click listener implemented by context should still be invoked for compatibility.
+ Annotation link = new Annotation("link", "foobar");
+ SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
+ ssb.setSpan(link, 1, 2, 0 /* flags */);
+
+ TestContext context = new TestContext(application);
+ context.delegate = mock(LinkSpan.OnClickListener.class);
+ RichTextView textView = new RichTextView(context);
+ textView.setText(ssb);
+
+ CharSequence text = textView.getText();
+ LinkSpan[] spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class);
+ spans[0].onClick(textView);
+
+ verify(context.delegate).onClick(eq(spans[0]));
+ }
+
+ @Test
+ public void onTouchEvent_clickOnLinks_shouldReturnTrue() {
+ Annotation link = new Annotation("link", "foobar");
+ SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
+ ssb.setSpan(link, 0, 2, 0 /* flags */);
+
+ RichTextView textView = new RichTextView(application);
+ textView.setText(ssb);
+
+ TouchableLinkMovementMethod mockMovementMethod = mock(TouchableLinkMovementMethod.class);
+ textView.setMovementMethod(mockMovementMethod);
+
+ MotionEvent motionEvent = MotionEvent.obtain(123, 22, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ doReturn(motionEvent).when(mockMovementMethod).getLastTouchEvent();
+ doReturn(true).when(mockMovementMethod).isLastTouchEventHandled();
+ assertThat(textView.onTouchEvent(motionEvent)).isTrue();
+ }
+
+ @Test
+ public void onTouchEvent_clickOutsideLinks_shouldReturnFalse() {
+ Annotation link = new Annotation("link", "foobar");
+ SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
+ ssb.setSpan(link, 0, 2, 0 /* flags */);
+
+ RichTextView textView = new RichTextView(application);
+ textView.setText(ssb);
+
+ TouchableLinkMovementMethod mockMovementMethod = mock(TouchableLinkMovementMethod.class);
+ textView.setMovementMethod(mockMovementMethod);
+
+ MotionEvent motionEvent = MotionEvent.obtain(123, 22, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ doReturn(motionEvent).when(mockMovementMethod).getLastTouchEvent();
+ doReturn(false).when(mockMovementMethod).isLastTouchEventHandled();
+ assertThat(textView.onTouchEvent(motionEvent)).isFalse();
+ }
+
+ @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(application);
+ textView.setText(ssb);
+
+ final CharSequence text = textView.getText();
+ assertThat(text).isInstanceOf(Spanned.class);
+
+ Object[] spans = ((Spanned) text).getSpans(0, text.length(), Annotation.class);
+ assertThat(spans).isEmpty();
+
+ spans = ((Spanned) text).getSpans(0, text.length(), TextAppearanceSpan.class);
+ assertThat(spans).hasLength(1);
+ assertThat(spans[0]).isInstanceOf(TextAppearanceSpan.class);
+ }
+
+ @Test
+ public void testTextContainingLinksAreFocusable() {
+ Annotation testLink = new Annotation("link", "value");
+ SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("Linked");
+ spannableStringBuilder.setSpan(testLink, 0, 3, 0);
+
+ RichTextView view = new RichTextView(application);
+ view.setText(spannableStringBuilder);
+
+ assertThat(view.isFocusable()).named("view focusable").isTrue();
+ }
+
+ @SuppressLint("SetTextI18n") // It's OK. This is just a test.
+ @Test
+ public void testTextContainingNoLinksAreNotFocusable() {
+ RichTextView textView = new RichTextView(application);
+ textView.setText("Thou shall not be focusable!");
+
+ assertThat(textView.isFocusable()).named("view focusable").isFalse();
+ }
+
+ // 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 testRichTextViewFocusChangesWithTextChange() {
+ RichTextView textView = new RichTextView(application);
+ textView.setText("Thou shall not be focusable!");
+
+ assertThat(textView.isFocusable()).isFalse();
+ assertThat(textView.isFocusableInTouchMode()).isFalse();
+
+ SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("I am focusable");
+ spannableStringBuilder.setSpan(new Annotation("link", "focus:on_me"), 0, 1, 0);
+ textView.setText(spannableStringBuilder);
+ assertThat(textView.isFocusable()).isTrue();
+ if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) {
+ assertThat(textView.isFocusableInTouchMode()).isTrue();
+ assertThat(textView.getRevealOnFocusHint()).isFalse();
+ } else {
+ assertThat(textView.isFocusableInTouchMode()).isFalse();
}
+ }
- @Test
- public void testLegacyContextOnClickListener() {
- // Click listener implemented by context should still be invoked for compatibility.
- Annotation link = new Annotation("link", "foobar");
- SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
- ssb.setSpan(link, 1, 2, 0 /* flags */);
-
- TestContext context = spy(new TestContext(application));
- RichTextView textView = new RichTextView(context);
- textView.setText(ssb);
+ public static class TestContext extends ContextWrapper implements LinkSpan.OnClickListener {
- CharSequence text = textView.getText();
- LinkSpan[] spans = ((Spanned) text).getSpans(0, text.length(), LinkSpan.class);
- spans[0].onClick(textView);
+ LinkSpan.OnClickListener delegate;
- verify(context).onClick(eq(spans[0]));
+ public TestContext(Context base) {
+ super(base);
}
- @Test
- public void onTouchEvent_clickOnLinks_shouldReturnTrue() {
- Annotation link = new Annotation("link", "foobar");
- SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
- ssb.setSpan(link, 0, 2, 0 /* flags */);
-
- RichTextView textView = new RichTextView(application);
- textView.setText(ssb);
-
- TouchableLinkMovementMethod mockMovementMethod = mock(TouchableLinkMovementMethod.class);
- textView.setMovementMethod(mockMovementMethod);
-
- MotionEvent motionEvent =
- MotionEvent.obtain(123, 22, MotionEvent.ACTION_DOWN, 0, 0, 0);
- doReturn(motionEvent).when(mockMovementMethod).getLastTouchEvent();
- doReturn(true).when(mockMovementMethod).isLastTouchEventHandled();
- assertThat(textView.onTouchEvent(motionEvent)).isTrue();
- }
-
- @Test
- public void onTouchEvent_clickOutsideLinks_shouldReturnFalse() {
- Annotation link = new Annotation("link", "foobar");
- SpannableStringBuilder ssb = new SpannableStringBuilder("Hello world");
- ssb.setSpan(link, 0, 2, 0 /* flags */);
-
- RichTextView textView = new RichTextView(application);
- textView.setText(ssb);
-
- TouchableLinkMovementMethod mockMovementMethod = mock(TouchableLinkMovementMethod.class);
- textView.setMovementMethod(mockMovementMethod);
-
- MotionEvent motionEvent =
- MotionEvent.obtain(123, 22, MotionEvent.ACTION_DOWN, 0, 0, 0);
- doReturn(motionEvent).when(mockMovementMethod).getLastTouchEvent();
- doReturn(false).when(mockMovementMethod).isLastTouchEventHandled();
- assertThat(textView.onTouchEvent(motionEvent)).isFalse();
- }
-
- @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(application);
- 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 testTextContainingLinksAreFocusable() {
- Annotation testLink = new Annotation("link", "value");
- SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("Linked");
- spannableStringBuilder.setSpan(testLink, 0, 3, 0);
-
- RichTextView view = new RichTextView(application);
- 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(application);
- 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 testRichTextViewFocusChangesWithTextChange() {
- RichTextView textView = new RichTextView(application);
- textView.setText("Thou shall not be focusable!");
-
- assertFalse(textView.isFocusable());
- assertFalse(textView.isFocusableInTouchMode());
-
- SpannableStringBuilder spannableStringBuilder =
- new SpannableStringBuilder("I am focusable");
- spannableStringBuilder.setSpan(new Annotation("link", "focus:on_me"), 0, 1, 0);
- textView.setText(spannableStringBuilder);
- assertTrue(textView.isFocusable());
- if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) {
- assertTrue(textView.isFocusableInTouchMode());
- assertFalse(textView.getRevealOnFocusHint());
- } else {
- assertFalse(textView.isFocusableInTouchMode());
- }
- }
-
- public static class TestContext extends ContextWrapper implements LinkSpan.OnClickListener {
-
- public TestContext(Context base) {
- super(base);
- }
-
- @Override
- public void onClick(LinkSpan span) {
- // Ignore. Can be verified using Mockito
- }
+ @Override
+ public void onClick(LinkSpan span) {
+ if (delegate != null) {
+ delegate.onClick(span);
+ }
}
+ }
}
diff --git a/navigationbar/Android.bp b/navigationbar/Android.bp
deleted file mode 100644
index 3868fe1..0000000
--- a/navigationbar/Android.bp
+++ /dev/null
@@ -1,7 +0,0 @@
-android_library {
- name: "setup-wizard-navbar",
-
- sdk_version: "current",
- resource_dirs: ["res"],
- srcs: ["src/**/*.java"],
-}
diff --git a/navigationbar/AndroidManifest.xml b/navigationbar/AndroidManifest.xml
deleted file mode 100644
index f1029cf..0000000
--- a/navigationbar/AndroidManifest.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.setupwizard.navigationbar">
-</manifest>
diff --git a/navigationbar/common.mk b/navigationbar/common.mk
deleted file mode 100644
index bacc931..0000000
--- a/navigationbar/common.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Include this make file to build your application against this module.
-#
-# Make sure to include it after you've set all your desired LOCAL variables.
-# Note that you must explicitly set your LOCAL_RESOURCE_DIR before including this file.
-#
-# For example:
-#
-# LOCAL_RESOURCE_DIR := \
-# $(LOCAL_PATH)/res
-#
-# include frameworks/opt/setupwizard/navigationbar/common.mk
-#
-
-LOCAL_RESOURCE_DIR += $(call my-dir)/res
-LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.setupwizard.navigationbar
-LOCAL_STATIC_JAVA_LIBRARIES += setup-wizard-navbar
diff --git a/navigationbar/project.properties b/navigationbar/project.properties
deleted file mode 100644
index 823f52e..0000000
--- a/navigationbar/project.properties
+++ /dev/null
@@ -1 +0,0 @@
-android.library=true
diff --git a/navigationbar/res/drawable/setup_wizard_navbar_btn_bg.xml b/navigationbar/res/drawable/setup_wizard_navbar_btn_bg.xml
deleted file mode 100644
index 0fc46be..0000000
--- a/navigationbar/res/drawable/setup_wizard_navbar_btn_bg.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 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.
--->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight">
-</ripple>
diff --git a/navigationbar/res/layout/setup_wizard_navbar_layout.xml b/navigationbar/res/layout/setup_wizard_navbar_layout.xml
deleted file mode 100644
index 6bdb02d..0000000
--- a/navigationbar/res/layout/setup_wizard_navbar_layout.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 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"
- style="@style/setup_wizard_navbar_style" >
-
- <view
- class="com.android.setupwizard.navigationbar.SetupWizardNavBar$NavButton"
- style="@style/setup_wizard_navbar_button_style"
- android:id="@+id/setup_wizard_navbar_back"
- android:contentDescription="@string/setup_wizard_back_button_label"
- android:drawableStart="@drawable/setup_wizard_navbar_ic_back" />
-
- <View
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:visibility="invisible" />
-
- <view
- class="com.android.setupwizard.navigationbar.SetupWizardNavBar$NavButton"
- style="@style/setup_wizard_navbar_button_style"
- android:text="@string/setup_wizard_next_button_label"
- android:gravity="end|center_vertical"
- android:drawableEnd="@drawable/setup_wizard_navbar_ic_next"
- android:id="@+id/setup_wizard_navbar_next" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/navigationbar/res/values-af/strings.xml b/navigationbar/res/values-af/strings.xml
deleted file mode 100644
index 4f7af72..0000000
--- a/navigationbar/res/values-af/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Volgende"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Terug"</string>
-</resources>
diff --git a/navigationbar/res/values-am/strings.xml b/navigationbar/res/values-am/strings.xml
deleted file mode 100644
index d7c3353..0000000
--- a/navigationbar/res/values-am/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"ቀጣይ"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"ተመለስ"</string>
-</resources>
diff --git a/navigationbar/res/values-ar/strings.xml b/navigationbar/res/values-ar/strings.xml
deleted file mode 100644
index b84a0a7..0000000
--- a/navigationbar/res/values-ar/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"التالي"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"رجوع"</string>
-</resources>
diff --git a/navigationbar/res/values-az/strings.xml b/navigationbar/res/values-az/strings.xml
deleted file mode 100644
index 99f211c..0000000
--- a/navigationbar/res/values-az/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Növbəti"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Geri"</string>
-</resources>
diff --git a/navigationbar/res/values-b+sr+Latn/strings.xml b/navigationbar/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index 4dbd175..0000000
--- a/navigationbar/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Dalje"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Nazad"</string>
-</resources>
diff --git a/navigationbar/res/values-be/strings.xml b/navigationbar/res/values-be/strings.xml
deleted file mode 100644
index 3612fce..0000000
--- a/navigationbar/res/values-be/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Далей"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Назад"</string>
-</resources>
diff --git a/navigationbar/res/values-bg/strings.xml b/navigationbar/res/values-bg/strings.xml
deleted file mode 100644
index e28abf9..0000000
--- a/navigationbar/res/values-bg/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Напред"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Назад"</string>
-</resources>
diff --git a/navigationbar/res/values-bn/strings.xml b/navigationbar/res/values-bn/strings.xml
deleted file mode 100644
index b7db1f2..0000000
--- a/navigationbar/res/values-bn/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"পরবর্তী"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"পিছনে"</string>
-</resources>
diff --git a/navigationbar/res/values-bs/strings.xml b/navigationbar/res/values-bs/strings.xml
deleted file mode 100644
index 1475017..0000000
--- a/navigationbar/res/values-bs/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Naprijed"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Nazad"</string>
-</resources>
diff --git a/navigationbar/res/values-ca/strings.xml b/navigationbar/res/values-ca/strings.xml
deleted file mode 100644
index 697af97..0000000
--- a/navigationbar/res/values-ca/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Següent"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Enrere"</string>
-</resources>
diff --git a/navigationbar/res/values-cs/strings.xml b/navigationbar/res/values-cs/strings.xml
deleted file mode 100644
index 2f3938a..0000000
--- a/navigationbar/res/values-cs/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Další"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Zpět"</string>
-</resources>
diff --git a/navigationbar/res/values-da/strings.xml b/navigationbar/res/values-da/strings.xml
deleted file mode 100644
index 487c575..0000000
--- a/navigationbar/res/values-da/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Næste"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Tilbage"</string>
-</resources>
diff --git a/navigationbar/res/values-de/strings.xml b/navigationbar/res/values-de/strings.xml
deleted file mode 100644
index e1e009f..0000000
--- a/navigationbar/res/values-de/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Weiter"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Zurück"</string>
-</resources>
diff --git a/navigationbar/res/values-el/strings.xml b/navigationbar/res/values-el/strings.xml
deleted file mode 100644
index 77aa32b..0000000
--- a/navigationbar/res/values-el/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Επόμενο"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Πίσω"</string>
-</resources>
diff --git a/navigationbar/res/values-en-rAU/strings.xml b/navigationbar/res/values-en-rAU/strings.xml
deleted file mode 100644
index b06dc86..0000000
--- a/navigationbar/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Next"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Back"</string>
-</resources>
diff --git a/navigationbar/res/values-en-rCA/strings.xml b/navigationbar/res/values-en-rCA/strings.xml
deleted file mode 100644
index b06dc86..0000000
--- a/navigationbar/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Next"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Back"</string>
-</resources>
diff --git a/navigationbar/res/values-en-rGB/strings.xml b/navigationbar/res/values-en-rGB/strings.xml
deleted file mode 100644
index b06dc86..0000000
--- a/navigationbar/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Next"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Back"</string>
-</resources>
diff --git a/navigationbar/res/values-en-rIN/strings.xml b/navigationbar/res/values-en-rIN/strings.xml
deleted file mode 100644
index b06dc86..0000000
--- a/navigationbar/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Next"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Back"</string>
-</resources>
diff --git a/navigationbar/res/values-en-rXC/strings.xml b/navigationbar/res/values-en-rXC/strings.xml
deleted file mode 100644
index 8107182..0000000
--- a/navigationbar/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎Next‎‏‎‎‏‎"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎Back‎‏‎‎‏‎"</string>
-</resources>
diff --git a/navigationbar/res/values-es-rUS/strings.xml b/navigationbar/res/values-es-rUS/strings.xml
deleted file mode 100644
index 3a23344..0000000
--- a/navigationbar/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Siguiente"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Atrás"</string>
-</resources>
diff --git a/navigationbar/res/values-es/strings.xml b/navigationbar/res/values-es/strings.xml
deleted file mode 100644
index 3a23344..0000000
--- a/navigationbar/res/values-es/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Siguiente"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Atrás"</string>
-</resources>
diff --git a/navigationbar/res/values-et/strings.xml b/navigationbar/res/values-et/strings.xml
deleted file mode 100644
index 7413fec..0000000
--- a/navigationbar/res/values-et/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Järgmine"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Tagasi"</string>
-</resources>
diff --git a/navigationbar/res/values-eu/strings.xml b/navigationbar/res/values-eu/strings.xml
deleted file mode 100644
index c108751..0000000
--- a/navigationbar/res/values-eu/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Hurrengoa"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Aurrekoa"</string>
-</resources>
diff --git a/navigationbar/res/values-fa/strings.xml b/navigationbar/res/values-fa/strings.xml
deleted file mode 100644
index 88c2a83..0000000
--- a/navigationbar/res/values-fa/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"بعدی"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"برگشت"</string>
-</resources>
diff --git a/navigationbar/res/values-fi/strings.xml b/navigationbar/res/values-fi/strings.xml
deleted file mode 100644
index 1bf32f2..0000000
--- a/navigationbar/res/values-fi/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Seuraava"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Edellinen"</string>
-</resources>
diff --git a/navigationbar/res/values-fr-rCA/strings.xml b/navigationbar/res/values-fr-rCA/strings.xml
deleted file mode 100644
index cea38c0..0000000
--- a/navigationbar/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Suivant"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Précédent"</string>
-</resources>
diff --git a/navigationbar/res/values-fr/strings.xml b/navigationbar/res/values-fr/strings.xml
deleted file mode 100644
index cea38c0..0000000
--- a/navigationbar/res/values-fr/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Suivant"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Précédent"</string>
-</resources>
diff --git a/navigationbar/res/values-gl/strings.xml b/navigationbar/res/values-gl/strings.xml
deleted file mode 100644
index 52e9248..0000000
--- a/navigationbar/res/values-gl/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Seguinte"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Atrás"</string>
-</resources>
diff --git a/navigationbar/res/values-gu/strings.xml b/navigationbar/res/values-gu/strings.xml
deleted file mode 100644
index aa3efe8..0000000
--- a/navigationbar/res/values-gu/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"આગલું"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"પાછળ"</string>
-</resources>
diff --git a/navigationbar/res/values-hi/strings.xml b/navigationbar/res/values-hi/strings.xml
deleted file mode 100644
index f8e9f9d..0000000
--- a/navigationbar/res/values-hi/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"आगे बढ़ें"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"पीछे"</string>
-</resources>
diff --git a/navigationbar/res/values-hr/strings.xml b/navigationbar/res/values-hr/strings.xml
deleted file mode 100644
index 071e451..0000000
--- a/navigationbar/res/values-hr/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Dalje"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Natrag"</string>
-</resources>
diff --git a/navigationbar/res/values-hu/strings.xml b/navigationbar/res/values-hu/strings.xml
deleted file mode 100644
index ed8349d..0000000
--- a/navigationbar/res/values-hu/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Következő"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Vissza"</string>
-</resources>
diff --git a/navigationbar/res/values-hy/strings.xml b/navigationbar/res/values-hy/strings.xml
deleted file mode 100644
index 4dd2fd5..0000000
--- a/navigationbar/res/values-hy/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Հաջորդը"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Հետ"</string>
-</resources>
diff --git a/navigationbar/res/values-in/strings.xml b/navigationbar/res/values-in/strings.xml
deleted file mode 100644
index bc6bc1e..0000000
--- a/navigationbar/res/values-in/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Berikutnya"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Kembali"</string>
-</resources>
diff --git a/navigationbar/res/values-is/strings.xml b/navigationbar/res/values-is/strings.xml
deleted file mode 100644
index 22d32b7..0000000
--- a/navigationbar/res/values-is/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Áfram"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Til baka"</string>
-</resources>
diff --git a/navigationbar/res/values-it/strings.xml b/navigationbar/res/values-it/strings.xml
deleted file mode 100644
index 0b61a83..0000000
--- a/navigationbar/res/values-it/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Avanti"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Indietro"</string>
-</resources>
diff --git a/navigationbar/res/values-iw/strings.xml b/navigationbar/res/values-iw/strings.xml
deleted file mode 100644
index 93f956e..0000000
--- a/navigationbar/res/values-iw/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"הבא"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"הקודם"</string>
-</resources>
diff --git a/navigationbar/res/values-ja/strings.xml b/navigationbar/res/values-ja/strings.xml
deleted file mode 100644
index 430a0cf..0000000
--- a/navigationbar/res/values-ja/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"次へ"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"戻る"</string>
-</resources>
diff --git a/navigationbar/res/values-ka/strings.xml b/navigationbar/res/values-ka/strings.xml
deleted file mode 100644
index 8263905..0000000
--- a/navigationbar/res/values-ka/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"შემდეგი"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"უკან"</string>
-</resources>
diff --git a/navigationbar/res/values-kk/strings.xml b/navigationbar/res/values-kk/strings.xml
deleted file mode 100644
index 358dadb..0000000
--- a/navigationbar/res/values-kk/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Келесі"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Артқа"</string>
-</resources>
diff --git a/navigationbar/res/values-km/strings.xml b/navigationbar/res/values-km/strings.xml
deleted file mode 100644
index 480e4d4..0000000
--- a/navigationbar/res/values-km/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"បន្ទាប់"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"ថយក្រោយ"</string>
-</resources>
diff --git a/navigationbar/res/values-kn/strings.xml b/navigationbar/res/values-kn/strings.xml
deleted file mode 100644
index 333e1a2..0000000
--- a/navigationbar/res/values-kn/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"ಮುಂದೆ"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"ಹಿಂದೆ"</string>
-</resources>
diff --git a/navigationbar/res/values-ko/strings.xml b/navigationbar/res/values-ko/strings.xml
deleted file mode 100644
index 66510cc..0000000
--- a/navigationbar/res/values-ko/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"다음"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"뒤로"</string>
-</resources>
diff --git a/navigationbar/res/values-ky/strings.xml b/navigationbar/res/values-ky/strings.xml
deleted file mode 100644
index ee8e164..0000000
--- a/navigationbar/res/values-ky/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Кийинки"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Артка"</string>
-</resources>
diff --git a/navigationbar/res/values-lo/strings.xml b/navigationbar/res/values-lo/strings.xml
deleted file mode 100644
index fc2ce83..0000000
--- a/navigationbar/res/values-lo/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"ຕໍ່ໄປ"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"ກັບຄືນ"</string>
-</resources>
diff --git a/navigationbar/res/values-lt/strings.xml b/navigationbar/res/values-lt/strings.xml
deleted file mode 100644
index 183404c..0000000
--- a/navigationbar/res/values-lt/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Kitas"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Atgal"</string>
-</resources>
diff --git a/navigationbar/res/values-lv/strings.xml b/navigationbar/res/values-lv/strings.xml
deleted file mode 100644
index 2aa72ee..0000000
--- a/navigationbar/res/values-lv/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Tālāk"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Atpakaļ"</string>
-</resources>
diff --git a/navigationbar/res/values-mk/strings.xml b/navigationbar/res/values-mk/strings.xml
deleted file mode 100644
index 52c8324..0000000
--- a/navigationbar/res/values-mk/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Следно"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Назад"</string>
-</resources>
diff --git a/navigationbar/res/values-ml/strings.xml b/navigationbar/res/values-ml/strings.xml
deleted file mode 100644
index a1373bc..0000000
--- a/navigationbar/res/values-ml/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"അടുത്തത്"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"മടങ്ങുക"</string>
-</resources>
diff --git a/navigationbar/res/values-mn/strings.xml b/navigationbar/res/values-mn/strings.xml
deleted file mode 100644
index e8099ce..0000000
--- a/navigationbar/res/values-mn/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Дараах"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Буцах"</string>
-</resources>
diff --git a/navigationbar/res/values-mr/strings.xml b/navigationbar/res/values-mr/strings.xml
deleted file mode 100644
index 3668c64..0000000
--- a/navigationbar/res/values-mr/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"पुढील"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"मागे"</string>
-</resources>
diff --git a/navigationbar/res/values-ms/strings.xml b/navigationbar/res/values-ms/strings.xml
deleted file mode 100644
index d801b6d..0000000
--- a/navigationbar/res/values-ms/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Seterusnya"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Kembali"</string>
-</resources>
diff --git a/navigationbar/res/values-my/strings.xml b/navigationbar/res/values-my/strings.xml
deleted file mode 100644
index 8c5944f..0000000
--- a/navigationbar/res/values-my/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"ရှေ့သို့"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"နောက်သို့"</string>
-</resources>
diff --git a/navigationbar/res/values-nb/strings.xml b/navigationbar/res/values-nb/strings.xml
deleted file mode 100644
index c1b7b0c..0000000
--- a/navigationbar/res/values-nb/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Neste"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Tilbake"</string>
-</resources>
diff --git a/navigationbar/res/values-ne/strings.xml b/navigationbar/res/values-ne/strings.xml
deleted file mode 100644
index d806032..0000000
--- a/navigationbar/res/values-ne/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"अर्को"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"पछाडि"</string>
-</resources>
diff --git a/navigationbar/res/values-nl/strings.xml b/navigationbar/res/values-nl/strings.xml
deleted file mode 100644
index 4f7af72..0000000
--- a/navigationbar/res/values-nl/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Volgende"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Terug"</string>
-</resources>
diff --git a/navigationbar/res/values-pa/strings.xml b/navigationbar/res/values-pa/strings.xml
deleted file mode 100644
index f1a53bc..0000000
--- a/navigationbar/res/values-pa/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"ਅੱਗੇ"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"ਪਿੱਛੇ"</string>
-</resources>
diff --git a/navigationbar/res/values-pl/strings.xml b/navigationbar/res/values-pl/strings.xml
deleted file mode 100644
index f47a9a7..0000000
--- a/navigationbar/res/values-pl/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Dalej"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Wstecz"</string>
-</resources>
diff --git a/navigationbar/res/values-pt-rBR/strings.xml b/navigationbar/res/values-pt-rBR/strings.xml
deleted file mode 100644
index 181fafe..0000000
--- a/navigationbar/res/values-pt-rBR/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Próxima"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Voltar"</string>
-</resources>
diff --git a/navigationbar/res/values-pt-rPT/strings.xml b/navigationbar/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 6be511f..0000000
--- a/navigationbar/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Seguinte"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Anterior"</string>
-</resources>
diff --git a/navigationbar/res/values-pt/strings.xml b/navigationbar/res/values-pt/strings.xml
deleted file mode 100644
index 181fafe..0000000
--- a/navigationbar/res/values-pt/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Próxima"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Voltar"</string>
-</resources>
diff --git a/navigationbar/res/values-ro/strings.xml b/navigationbar/res/values-ro/strings.xml
deleted file mode 100644
index 1c75ba8..0000000
--- a/navigationbar/res/values-ro/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Înainte"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Înapoi"</string>
-</resources>
diff --git a/navigationbar/res/values-ru/strings.xml b/navigationbar/res/values-ru/strings.xml
deleted file mode 100644
index 454613a..0000000
--- a/navigationbar/res/values-ru/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Далее"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Назад"</string>
-</resources>
diff --git a/navigationbar/res/values-si/strings.xml b/navigationbar/res/values-si/strings.xml
deleted file mode 100644
index 892a100..0000000
--- a/navigationbar/res/values-si/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"මීළඟ"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"ආපසු"</string>
-</resources>
diff --git a/navigationbar/res/values-sk/strings.xml b/navigationbar/res/values-sk/strings.xml
deleted file mode 100644
index 6d8e36d..0000000
--- a/navigationbar/res/values-sk/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Ďalej"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Späť"</string>
-</resources>
diff --git a/navigationbar/res/values-sl/strings.xml b/navigationbar/res/values-sl/strings.xml
deleted file mode 100644
index ebc916a..0000000
--- a/navigationbar/res/values-sl/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Naprej"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Nazaj"</string>
-</resources>
diff --git a/navigationbar/res/values-sq/strings.xml b/navigationbar/res/values-sq/strings.xml
deleted file mode 100644
index 7f4f95d..0000000
--- a/navigationbar/res/values-sq/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Përpara"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Prapa"</string>
-</resources>
diff --git a/navigationbar/res/values-sr/strings.xml b/navigationbar/res/values-sr/strings.xml
deleted file mode 100644
index 531d772..0000000
--- a/navigationbar/res/values-sr/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Даље"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Назад"</string>
-</resources>
diff --git a/navigationbar/res/values-sv/strings.xml b/navigationbar/res/values-sv/strings.xml
deleted file mode 100644
index db88fdc..0000000
--- a/navigationbar/res/values-sv/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Nästa"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Föregående"</string>
-</resources>
diff --git a/navigationbar/res/values-sw/strings.xml b/navigationbar/res/values-sw/strings.xml
deleted file mode 100644
index c02d768..0000000
--- a/navigationbar/res/values-sw/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Endelea"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Rudi nyuma"</string>
-</resources>
diff --git a/navigationbar/res/values-ta/strings.xml b/navigationbar/res/values-ta/strings.xml
deleted file mode 100644
index 3e3ef59..0000000
--- a/navigationbar/res/values-ta/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"அடுத்து"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"பின்செல்"</string>
-</resources>
diff --git a/navigationbar/res/values-te/strings.xml b/navigationbar/res/values-te/strings.xml
deleted file mode 100644
index fdf5c75..0000000
--- a/navigationbar/res/values-te/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"తర్వాత"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"వెనుకకు"</string>
-</resources>
diff --git a/navigationbar/res/values-th/strings.xml b/navigationbar/res/values-th/strings.xml
deleted file mode 100644
index d926d6d..0000000
--- a/navigationbar/res/values-th/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"ถัดไป"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"กลับ"</string>
-</resources>
diff --git a/navigationbar/res/values-tl/strings.xml b/navigationbar/res/values-tl/strings.xml
deleted file mode 100644
index 68b8a43..0000000
--- a/navigationbar/res/values-tl/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Susunod"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Bumalik"</string>
-</resources>
diff --git a/navigationbar/res/values-tr/strings.xml b/navigationbar/res/values-tr/strings.xml
deleted file mode 100644
index 5e667b6..0000000
--- a/navigationbar/res/values-tr/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"İleri"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Geri"</string>
-</resources>
diff --git a/navigationbar/res/values-uk/strings.xml b/navigationbar/res/values-uk/strings.xml
deleted file mode 100644
index 9133704..0000000
--- a/navigationbar/res/values-uk/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Далі"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Назад"</string>
-</resources>
diff --git a/navigationbar/res/values-ur/strings.xml b/navigationbar/res/values-ur/strings.xml
deleted file mode 100644
index 00825ab..0000000
--- a/navigationbar/res/values-ur/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"آگے"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"پیچھے"</string>
-</resources>
diff --git a/navigationbar/res/values-uz/strings.xml b/navigationbar/res/values-uz/strings.xml
deleted file mode 100644
index 0f9e086..0000000
--- a/navigationbar/res/values-uz/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Keyingisi"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Orqaga"</string>
-</resources>
diff --git a/navigationbar/res/values-vi/strings.xml b/navigationbar/res/values-vi/strings.xml
deleted file mode 100644
index 3e822ec..0000000
--- a/navigationbar/res/values-vi/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Tiếp theo"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Quay lại"</string>
-</resources>
diff --git a/navigationbar/res/values-zh-rCN/strings.xml b/navigationbar/res/values-zh-rCN/strings.xml
deleted file mode 100644
index e7e2394..0000000
--- a/navigationbar/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"下一步"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"返回"</string>
-</resources>
diff --git a/navigationbar/res/values-zh-rHK/strings.xml b/navigationbar/res/values-zh-rHK/strings.xml
deleted file mode 100644
index e7e2394..0000000
--- a/navigationbar/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"下一步"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"返回"</string>
-</resources>
diff --git a/navigationbar/res/values-zh-rTW/strings.xml b/navigationbar/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 56ae800..0000000
--- a/navigationbar/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"繼續"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"返回"</string>
-</resources>
diff --git a/navigationbar/res/values-zu/strings.xml b/navigationbar/res/values-zu/strings.xml
deleted file mode 100644
index b5b0eee..0000000
--- a/navigationbar/res/values-zu/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="setup_wizard_next_button_label" msgid="6681282266022780599">"Okulandelayo"</string>
- <string name="setup_wizard_back_button_label" msgid="2863826823307023546">"Phindela emuva"</string>
-</resources>
diff --git a/navigationbar/res/values/colors.xml b/navigationbar/res/values/colors.xml
deleted file mode 100644
index 1cdf964..0000000
--- a/navigationbar/res/values/colors.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <color name="setup_wizard_navbar_bg_dark">#ff21272b</color>
- <color name="setup_wizard_navbar_bg_light">#ffe4e7e9</color>
- <color name="setup_wizard_navbar_text_dark">#deffffff</color>
- <color name="setup_wizard_navbar_text_light">#de000000</color>
-</resources>
diff --git a/navigationbar/res/values/dimens.xml b/navigationbar/res/values/dimens.xml
deleted file mode 100644
index df67d9f..0000000
--- a/navigationbar/res/values/dimens.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <dimen name="setup_wizard_navbar_button_drawable_padding">6dp</dimen>
- <dimen name="setup_wizard_navbar_button_padding_sides">10dp</dimen>
- <dimen name="setup_wizard_navbar_height">56dp</dimen>
- <dimen name="setup_wizard_navbar_ic_intrinsic_size">24dp</dimen>
- <dimen name="setup_wizard_navbar_padding_sides">24dp</dimen>
- <dimen name="setup_wizard_navbar_text_size">16sp</dimen>
-</resources>
diff --git a/navigationbar/res/values/strings.xml b/navigationbar/res/values/strings.xml
deleted file mode 100644
index 7f01c4e..0000000
--- a/navigationbar/res/values/strings.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- Button for going to the next screen or step [CHAR LIMIT=40] -->
- <string name="setup_wizard_next_button_label">Next</string>
-
- <!-- Button for going to the previous screen or step [CHAR LIMIT=40] -->
- <string name="setup_wizard_back_button_label">Back</string>
-
-</resources>
diff --git a/navigationbar/res/values/styles.xml b/navigationbar/res/values/styles.xml
deleted file mode 100644
index 9aa9a85..0000000
--- a/navigationbar/res/values/styles.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <attr name="setup_wizard_navbar_bg_color" format="color" />
- <attr name="setup_wizard_navbar_text_color" format="color" />
- <attr name="setup_wizard_navbar_theme" format="reference" />
-
- <style name="setup_wizard_navbar_style">
- <item name="android:orientation">horizontal</item>
- <item name="android:layout_height">@dimen/setup_wizard_navbar_height</item>
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_alignParentBottom">true</item>
- <item name="android:background">?attr/setup_wizard_navbar_bg_color</item>
- <item name="android:paddingStart">@dimen/setup_wizard_navbar_padding_sides</item>
- <item name="android:paddingEnd">@dimen/setup_wizard_navbar_padding_sides</item>
- </style>
-
- <style name="setup_wizard_navbar_theme_dark">
- <item name="setup_wizard_navbar_bg_color">@color/setup_wizard_navbar_bg_dark</item>
- <item name="setup_wizard_navbar_text_color">@color/setup_wizard_navbar_text_dark</item>
- </style>
-
- <style name="setup_wizard_navbar_theme_light">
- <item name="setup_wizard_navbar_bg_color">@color/setup_wizard_navbar_bg_light</item>
- <item name="setup_wizard_navbar_text_color">@color/setup_wizard_navbar_text_light</item>
- </style>
-
- <style name="setup_wizard_navbar_button_style" parent="@android:style/Widget.Material.Button.Borderless">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">match_parent</item>
- <item name="android:layout_weight">0</item>
- <item name="android:background">@drawable/setup_wizard_navbar_btn_bg</item>
- <item name="android:drawablePadding">@dimen/setup_wizard_navbar_button_drawable_padding</item>
- <item name="android:fontFamily">sans-serif</item>
- <item name="android:minWidth">0dp</item>
- <item name="android:paddingEnd">@dimen/setup_wizard_navbar_button_padding_sides</item>
- <item name="android:paddingStart">@dimen/setup_wizard_navbar_button_padding_sides</item>
- <item name="android:textAllCaps">true</item>
- <item name="android:textColor">?attr/setup_wizard_navbar_text_color</item>
- <item name="android:textSize">@dimen/setup_wizard_navbar_text_size</item>
- </style>
-
-</resources>
diff --git a/navigationbar/src/com/android/setupwizard/navigationbar/SetupWizardNavBar.java b/navigationbar/src/com/android/setupwizard/navigationbar/SetupWizardNavBar.java
deleted file mode 100644
index e34ad6c..0000000
--- a/navigationbar/src/com/android/setupwizard/navigationbar/SetupWizardNavBar.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2014 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.setupwizard.navigationbar;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.view.ContextThemeWrapper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnPreDrawListener;
-import android.widget.Button;
-
-/**
- * Fragment class for controlling the custom navigation bar shown during setup wizard. Apps in the
- * Android tree can use this by including the common.mk makefile. Apps outside of the tree can
- * create a library project out of the source.
- */
-public class SetupWizardNavBar extends Fragment implements OnPreDrawListener, OnClickListener {
- private static final String TAG = "SetupWizardNavBar";
- private static final int IMMERSIVE_FLAGS =
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- private int mSystemUiFlags = IMMERSIVE_FLAGS | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-
- private ViewGroup mNavigationBarView;
- private Button mNextButton;
- private Button mBackButton;
- private NavigationBarListener mCallback;
-
- public interface NavigationBarListener {
- public void onNavigationBarCreated(SetupWizardNavBar bar);
- public void onNavigateBack();
- public void onNavigateNext();
- }
-
- public SetupWizardNavBar() {
- // no-arg constructor for fragments
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mCallback = (NavigationBarListener) activity;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- Context context = new ContextThemeWrapper(getActivity(), getNavbarTheme());
- inflater = LayoutInflater.from(context);
- mNavigationBarView = (ViewGroup) inflater.inflate(R.layout.setup_wizard_navbar_layout,
- container, false);
- mNextButton = (Button) mNavigationBarView.findViewById(R.id.setup_wizard_navbar_next);
- mBackButton = (Button) mNavigationBarView.findViewById(R.id.setup_wizard_navbar_back);
- mNextButton.setOnClickListener(this);
- mBackButton.setOnClickListener(this);
- return mNavigationBarView;
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- mCallback.onNavigationBarCreated(this);
- mNavigationBarView.setSystemUiVisibility(mSystemUiFlags);
-
- // Set the UI flags before draw because the visibility might change in unexpected /
- // undetectable times, like transitioning from a finishing activity that had a keyboard
- ViewTreeObserver viewTreeObserver = mNavigationBarView.getViewTreeObserver();
- viewTreeObserver.addOnPreDrawListener(this);
- }
-
- @Override
- public boolean onPreDraw() {
- // View.setSystemUiVisibility checks if the visibility changes before applying them
- // so the performance impact is contained
- mNavigationBarView.setSystemUiVisibility(mSystemUiFlags);
- return true;
- }
-
- /**
- * Sets whether system navigation bar should be hidden.
- * @param useImmersiveMode True to activate immersive mode and hide the system navigation bar
- */
- public void setUseImmersiveMode(boolean useImmersiveMode) {
- // By default, enable layoutHideNavigation if immersive mode is used
- setUseImmersiveMode(useImmersiveMode, useImmersiveMode);
- }
-
- public void setUseImmersiveMode(boolean useImmersiveMode, boolean layoutHideNavigation) {
- if (useImmersiveMode) {
- mSystemUiFlags |= IMMERSIVE_FLAGS;
- if (layoutHideNavigation) {
- mSystemUiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- }
- } else {
- mSystemUiFlags &= ~(IMMERSIVE_FLAGS | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- }
- mNavigationBarView.setSystemUiVisibility(mSystemUiFlags);
- }
-
- private int getNavbarTheme() {
- // Normally we can automatically guess the theme by comparing the foreground color against
- // the background color. But we also allow specifying explicitly using
- // setup_wizard_navbar_theme.
- TypedArray attributes = getActivity().obtainStyledAttributes(
- new int[] {
- R.attr.setup_wizard_navbar_theme,
- android.R.attr.colorForeground,
- android.R.attr.colorBackground });
- int theme = attributes.getResourceId(0, 0);
- if (theme == 0) {
- // Compare the value of the foreground against the background color to see if current
- // theme is light-on-dark or dark-on-light.
- float[] foregroundHsv = new float[3];
- float[] backgroundHsv = new float[3];
- Color.colorToHSV(attributes.getColor(1, 0), foregroundHsv);
- Color.colorToHSV(attributes.getColor(2, 0), backgroundHsv);
- boolean isDarkBg = foregroundHsv[2] > backgroundHsv[2];
- theme = isDarkBg ? R.style.setup_wizard_navbar_theme_dark :
- R.style.setup_wizard_navbar_theme_light;
- }
- attributes.recycle();
- return theme;
- }
-
- @Override
- public void onClick(View v) {
- if (v == mBackButton) {
- mCallback.onNavigateBack();
- } else if (v == mNextButton) {
- mCallback.onNavigateNext();
- }
- }
-
- public Button getBackButton() {
- return mBackButton;
- }
-
- public Button getNextButton() {
- return mNextButton;
- }
-
- public static class NavButton extends Button {
-
- public NavButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- public NavButton(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public NavButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public NavButton(Context context) {
- super(context);
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- // The color of the button is #de000000 / #deffffff when enabled. When disabled, apply
- // additional 23% alpha, so the overall opacity is 20%.
- setAlpha(enabled ? 1.0f : 0.23f);
- }
- }
-
-}
diff --git a/tools/build_for_build_server.sh b/tools/build_for_build_server.sh
index 7a8c942..1ed4ea7 100755
--- a/tools/build_for_build_server.sh
+++ b/tools/build_for_build_server.sh
@@ -6,4 +6,4 @@ export TARGET_BUILD_DENSITY="alldpi"
export TARGET_BUILD_TYPE="release"
export TARGET_BUILD_APPS="setup-wizard-lib"
-./gradlew buildProjectFull test coverage
+./gradlew buildProjectFull test coverage --info
diff --git a/tools/checkstyle/checkstyle.xml b/tools/checkstyle/checkstyle.xml
deleted file mode 100644
index 0dbccae..0000000
--- a/tools/checkstyle/checkstyle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd" [
- <!ENTITY defaultCopyrightCheck SYSTEM "../../../../../prebuilts/checkstyle/default-copyright-check.xml">
- <!ENTITY defaultJavadocChecks SYSTEM "../../../../../prebuilts/checkstyle/default-javadoc-checks.xml">
- <!ENTITY defaultTreewalkerChecks SYSTEM "../../../../../prebuilts/checkstyle/default-treewalker-checks.xml">
- <!ENTITY defaultModuleChecks SYSTEM "../../../../../prebuilts/checkstyle/default-module-checks.xml">
-]>
-
-<module name="Checker">
- &defaultModuleChecks;
- &defaultCopyrightCheck;
- <module name="TreeWalker">
- &defaultJavadocChecks;
- &defaultTreewalkerChecks;
- </module>
-
- <module name="SuppressionFilter">
- <property name="file" value="tools/checkstyle/checkstyle_suppression.xml" />
- </module>
-</module>
diff --git a/tools/checkstyle/checkstyle_suppression.xml b/tools/checkstyle/checkstyle_suppression.xml
deleted file mode 100644
index 6bf7b21..0000000
--- a/tools/checkstyle/checkstyle_suppression.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN" "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
-<suppressions>
-
- <!-- Note: Checkstyle puts the absolute path of files through the suppress filter, so the
- patterns below will match sub-directories. Notably, for overlays where the path is
- something like overlay/frameworks/opt/setupwizard will match the regex filter
- "frameworks/opt/setupwizard". This is probably OK for most cases since they are overlay
- of the original app and should have the same coding style. -->
-
- <!-- Robolectric uses magic method names like `__constructor__` -->
- <suppress files="/robotest/" checks="MethodName" />
-
-</suppressions>