summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-02-17 02:57:07 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-02-17 02:57:07 +0000
commit9d7fac204ebeefc144fb4b74e5a99064d9aa8f86 (patch)
tree837e2b957b7ea9572732fa4af1d95d0cf1a0011a
parenta2ecba4b5cb51287d169f26c9b7ee38461c6b488 (diff)
parent4995a2ba9c0f260f383667cd389f2cdda7326eca (diff)
downloadsetupwizard-android13-frc-media-release.tar.gz
Snap for 8191477 from 4995a2ba9c0f260f383667cd389f2cdda7326eca to tm-frc-media-releaset_frc_med_330443030android13-frc-media-release
Change-Id: Ia21dd78c82ded1e3a8f1e7798716b634b64d4584
-rw-r--r--build.gradle47
-rw-r--r--gradle.properties32
-rw-r--r--library/main/Android.bp6
-rw-r--r--library/main/AndroidManifest.xml4
-rw-r--r--library/main/build.gradle1
-rw-r--r--library/main/res/color/button_text_color.xml23
-rw-r--r--library/main/res/drawable/flat_button_background.xml44
-rw-r--r--library/main/res/drawable/list_item_background.xml46
-rw-r--r--library/main/res/drawable/primary_button_background.xml54
-rw-r--r--library/main/res/drawable/round_button_background.xml46
-rw-r--r--library/main/res/layout-land/action_bar.xml38
-rw-r--r--library/main/res/layout-land/rotary_action_bar.xml38
-rw-r--r--library/main/res/layout-land/rotary_split_nav_layout.xml71
-rw-r--r--library/main/res/layout-land/split_nav_layout.xml60
-rw-r--r--library/main/res/layout-w1760dp-land/rotary_split_nav_layout.xml67
-rw-r--r--library/main/res/layout-w1760dp-land/split_nav_layout.xml57
-rw-r--r--library/main/res/layout/action_bar.xml36
-rw-r--r--library/main/res/layout/car_setup_wizard_toolbar.xml14
-rw-r--r--library/main/res/layout/empty_fragment_frame_layout.xml5
-rw-r--r--library/main/res/layout/progressbar.xml26
-rw-r--r--library/main/res/layout/rotary_car_setup_wizard_layout.xml39
-rw-r--r--library/main/res/layout/rotary_split_nav_layout.xml67
-rw-r--r--library/main/res/layout/split_nav_compat_activity.xml27
-rw-r--r--library/main/res/layout/split_nav_design_activity.xml27
-rw-r--r--library/main/res/layout/split_nav_layout.xml53
-rw-r--r--library/main/res/values/attrs.xml5
-rw-r--r--library/main/res/values/colors.xml8
-rw-r--r--library/main/res/values/dimens.xml8
-rw-r--r--library/main/res/values/styles.xml2
-rw-r--r--library/main/res/values/themes.xml8
-rw-r--r--library/main/src/com/android/car/setupwizardlib/BaseCompatActivity.java3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/BaseDesignActivity.java3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java71
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java264
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java2
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayoutInterface.java82
-rw-r--r--library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java5
-rw-r--r--library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigHelper.java2
-rw-r--r--library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java5
-rw-r--r--library/main/src/com/android/car/setupwizardlib/partner/ResourceEntry.java1
-rw-r--r--library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java6
-rw-r--r--library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java11
-rw-r--r--library/main/src/com/android/car/setupwizardlib/summary/SummaryActionState.java24
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/CarHelperRegistry.java2
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java265
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/FeatureResolver.java119
-rw-r--r--library/main/tests/robotests/Android.bp4
-rw-r--r--library/main/tests/robotests/res/layout/car_setup_wizard_layout_test_activity.xml4
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/BaseCompatActivityTest.java109
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java270
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/FakeFeatureManagementProvider.java94
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/SplitNavLayoutTest.java137
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/util/FeatureResolverTest.java136
-rw-r--r--library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java2
-rw-r--r--settings.gradle20
59 files changed, 2285 insertions, 327 deletions
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..9f39796
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+
+ }
+ dependencies {
+ // Before upgrading this version, make sure you can close android
+ // studio, run git clean -fxd, and then reopen this folder in android
+ // studio and have it work. Sometimes android studio's built in gradle
+ // wrapper seems to lag behind the version required by the android
+ // plugin.
+ classpath 'com.android.tools.build:gradle:4.1.3'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..2a103f9
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2021 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.
+
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
diff --git a/library/main/Android.bp b/library/main/Android.bp
index f99ecdd..506dee5 100644
--- a/library/main/Android.bp
+++ b/library/main/Android.bp
@@ -22,7 +22,11 @@ android_library {
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
libs: ["android.car-system-stubs"],
- static_libs: ["androidx.car_car-resources-partially-dejetified"],
+ static_libs: [
+ "androidx.car_car-resources-partially-dejetified",
+ "car-ui-lib",
+ "androidx.test.core"
+ ],
optimize: {
enabled: false,
},
diff --git a/library/main/AndroidManifest.xml b/library/main/AndroidManifest.xml
index 9bd2e16..e330c33 100644
--- a/library/main/AndroidManifest.xml
+++ b/library/main/AndroidManifest.xml
@@ -18,6 +18,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.car.setupwizardlib">
<uses-sdk
- android:minSdkVersion="24"
- android:targetSdkVersion="26" />
+ android:minSdkVersion="29"
+ android:targetSdkVersion="31" />
</manifest>
diff --git a/library/main/build.gradle b/library/main/build.gradle
index 412e3b0..17ab59a 100644
--- a/library/main/build.gradle
+++ b/library/main/build.gradle
@@ -78,6 +78,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.core:core:1.3.2'
implementation 'androidx.annotation:annotation:1.2.0'
+ implementation 'androidx.test:core:1.4.0'
testImplementation 'com.google.truth:truth:0.41'
testImplementation 'org.mockito:mockito-core:3.6.0'
diff --git a/library/main/res/color/button_text_color.xml b/library/main/res/color/button_text_color.xml
new file mode 100644
index 0000000..f4ed692
--- /dev/null
+++ b/library/main/res/color/button_text_color.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:color="@android:color/white"/>
+ <item android:state_enabled="false"
+ android:alpha="0.5"
+ android:color="@android:color/black"/>
+ <item android:color="@android:color/black"/>
+</selector> \ No newline at end of file
diff --git a/library/main/res/drawable/flat_button_background.xml b/library/main/res/drawable/flat_button_background.xml
new file mode 100644
index 0000000..ff5dbdc
--- /dev/null
+++ b/library/main/res/drawable/flat_button_background.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/suw_rotary_focus_pressed_fill_color"/>
+ <stroke android:width="@dimen/suw_rotary_focus_pressed_stroke_width"
+ android:color="@color/suw_rotary_focus_pressed_stroke_color" />
+ <corners android:radius="@dimen/car_button_radius"/>
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/suw_rotary_focus_fill_color"/>
+ <stroke android:width="@dimen/suw_rotary_focus_stroke_width"
+ android:color="@color/suw_rotary_focus_stroke_color" />
+ <corners android:radius="@dimen/car_button_radius"/>
+ </shape>
+ </item>
+ <item>
+ <ripple android:color="@color/car_grey_300">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/car_button_radius"/>
+ <solid android:color="@color/car_card_ripple_background_light"/>
+ </shape>
+ </item>
+ </ripple>
+ </item>
+</selector>
diff --git a/library/main/res/drawable/list_item_background.xml b/library/main/res/drawable/list_item_background.xml
new file mode 100644
index 0000000..9f871dd
--- /dev/null
+++ b/library/main/res/drawable/list_item_background.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/suw_rotary_focus_pressed_fill_color"/>
+ <stroke android:width="@dimen/suw_rotary_focus_pressed_stroke_width"
+ android:color="@color/suw_rotary_focus_pressed_stroke_color"/>
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/suw_rotary_focus_fill_color"/>
+ <stroke android:width="@dimen/suw_rotary_focus_stroke_width"
+ android:color="@color/suw_rotary_focus_stroke_color"/>
+ </shape>
+ </item>
+ <item android:state_activated="true">
+ <shape android:shape="rectangle">
+ <solid android:color="?android:attr/colorControlHighlight"/>
+ </shape>
+ </item>
+ <item>
+ <ripple android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/car_card_ripple_background_light"/>
+ </shape>
+ </item>
+ </ripple>
+ </item>
+</selector> \ No newline at end of file
diff --git a/library/main/res/drawable/primary_button_background.xml b/library/main/res/drawable/primary_button_background.xml
new file mode 100644
index 0000000..e353b9c
--- /dev/null
+++ b/library/main/res/drawable/primary_button_background.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/suw_rotary_focus_pressed_fill_color"/>
+ <stroke android:width="@dimen/suw_rotary_focus_pressed_stroke_width"
+ android:color="@color/suw_rotary_focus_pressed_stroke_color" />
+ <corners android:radius="@dimen/car_button_radius"/>
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/suw_rotary_focus_fill_color"/>
+ <stroke android:width="@dimen/suw_rotary_focus_stroke_width"
+ android:color="@color/suw_rotary_focus_stroke_color" />
+ <corners android:radius="@dimen/car_button_radius"/>
+ </shape>
+ </item>
+ <item>
+ <ripple android:color="?attr/colorControlHighlight">
+ <item>
+ <selector>
+ <item android:state_enabled="false">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/car_button_radius"/>
+ <solid android:color="@color/car_grey_300"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/car_button_radius"/>
+ <solid android:color="?android:attr/colorButtonNormal"/>
+ </shape>
+ </item>
+ </selector>
+ </item>
+ </ripple>
+ </item>
+</selector> \ No newline at end of file
diff --git a/library/main/res/drawable/round_button_background.xml b/library/main/res/drawable/round_button_background.xml
new file mode 100644
index 0000000..eedce1f
--- /dev/null
+++ b/library/main/res/drawable/round_button_background.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_pressed="true">
+ <shape android:shape="oval">
+ <solid android:color="@color/suw_rotary_focus_pressed_fill_color"/>
+ <stroke android:width="@dimen/suw_rotary_focus_pressed_stroke_width"
+ android:color="@color/suw_rotary_focus_pressed_stroke_color"/>
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="oval">
+ <solid android:color="@color/suw_rotary_focus_fill_color"/>
+ <stroke android:width="@dimen/suw_rotary_focus_stroke_width"
+ android:color="@color/suw_rotary_focus_stroke_color"/>
+ </shape>
+ </item>
+ <item android:state_activated="true">
+ <shape android:shape="oval">
+ <solid android:color="?android:attr/colorControlHighlight"/>
+ </shape>
+ </item>
+ <item>
+ <ripple android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="oval">
+ <solid android:color="@color/car_card_ripple_background_light"/>
+ </shape>
+ </item>
+ </ripple>
+ </item>
+</selector> \ No newline at end of file
diff --git a/library/main/res/layout-land/action_bar.xml b/library/main/res/layout-land/action_bar.xml
new file mode 100644
index 0000000..71929a5
--- /dev/null
+++ b/library/main/res/layout-land/action_bar.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/button_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/actionbar_height"
+ android:gravity="top"
+ android:paddingTop="@dimen/suw_padding_4"
+ android:paddingHorizontal="@dimen/suw_padding_7"
+ android:orientation="horizontal">
+ <ViewStub
+ android:id="@+id/primary_toolbar_button_stub"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:inflatedId="@+id/primary_toolbar_button"
+ android:layout="@layout/primary_button"/>
+ <ViewStub
+ android:id="@+id/secondary_toolbar_button_stub"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/suw_padding_7"
+ android:inflatedId="@+id/secondary_toolbar_button"
+ android:layout="@layout/flat_button"/>
+</LinearLayout> \ No newline at end of file
diff --git a/library/main/res/layout-land/rotary_action_bar.xml b/library/main/res/layout-land/rotary_action_bar.xml
new file mode 100644
index 0000000..8f02f29
--- /dev/null
+++ b/library/main/res/layout-land/rotary_action_bar.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<com.android.car.ui.FocusArea xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/button_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/actionbar_height"
+ android:gravity="top"
+ android:paddingTop="@dimen/suw_padding_4"
+ android:paddingHorizontal="@dimen/suw_padding_7"
+ android:orientation="horizontal">
+ <ViewStub
+ android:id="@+id/primary_toolbar_button_stub"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:inflatedId="@+id/primary_toolbar_button"
+ android:layout="@layout/primary_button"/>
+ <ViewStub
+ android:id="@+id/secondary_toolbar_button_stub"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/suw_padding_7"
+ android:inflatedId="@+id/secondary_toolbar_button"
+ android:layout="@layout/flat_button"/>
+</com.android.car.ui.FocusArea> \ No newline at end of file
diff --git a/library/main/res/layout-land/rotary_split_nav_layout.xml b/library/main/res/layout-land/rotary_split_nav_layout.xml
new file mode 100644
index 0000000..b69c5b2
--- /dev/null
+++ b/library/main/res/layout-land/rotary_split_nav_layout.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <com.android.car.ui.FocusParkingView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <com.android.car.ui.FocusArea
+ android:id="@+id/application_bar"
+ android:layout_width="@dimen/sidebar_width"
+ android:layout_height="match_parent"
+ android:gravity="top"
+ android:paddingTop="@dimen/suw_padding_3"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/back_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/round_button_background"
+ android:contentDescription="@string/back_button_content_description"
+ android:padding="@dimen/car_padding_2"
+ android:src="@drawable/car_ic_arrow_back"/>
+
+ <ImageView
+ android:id="@+id/close_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/round_button_background"
+ android:contentDescription="@string/close_button_content_description"
+ android:padding="@dimen/car_padding_2"
+ android:src="@drawable/car_ic_close"/>
+ </com.android.car.ui.FocusArea>
+
+ <LinearLayout
+ android:id="@+id/content_container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <include layout="@layout/progressbar"/>
+
+ <com.android.car.ui.FocusArea
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ <ViewStub
+ android:id="@+id/layout_content_stub"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </com.android.car.ui.FocusArea>
+
+ <include layout="@layout/rotary_action_bar"/>
+ </LinearLayout>
+</merge> \ No newline at end of file
diff --git a/library/main/res/layout-land/split_nav_layout.xml b/library/main/res/layout-land/split_nav_layout.xml
new file mode 100644
index 0000000..16a017f
--- /dev/null
+++ b/library/main/res/layout-land/split_nav_layout.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <FrameLayout
+ android:id="@+id/application_bar"
+ android:layout_width="@dimen/sidebar_width"
+ android:layout_height="match_parent"
+ android:gravity="top"
+ android:paddingTop="@dimen/suw_padding_3">
+
+ <ImageView
+ android:id="@+id/back_button"
+ android:layout_width="@dimen/car_primary_icon_size"
+ android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/button_ripple_bg"
+ android:contentDescription="@string/back_button_content_description"
+ android:src="@drawable/car_ic_arrow_back"/>
+
+ <ImageView
+ android:id="@+id/close_button"
+ android:layout_width="@dimen/car_primary_icon_size"
+ android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/button_ripple_bg"
+ android:contentDescription="@string/close_button_content_description"
+ android:src="@drawable/car_ic_close"/>
+ </FrameLayout>
+
+ <LinearLayout
+ android:id="@+id/content_container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <include layout="@layout/progressbar"/>
+
+ <ViewStub
+ android:id="@+id/layout_content_stub"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <include layout="@layout/action_bar"/>
+ </LinearLayout>
+</merge> \ No newline at end of file
diff --git a/library/main/res/layout-w1760dp-land/rotary_split_nav_layout.xml b/library/main/res/layout-w1760dp-land/rotary_split_nav_layout.xml
new file mode 100644
index 0000000..8ff4854
--- /dev/null
+++ b/library/main/res/layout-w1760dp-land/rotary_split_nav_layout.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <com.android.car.ui.FocusParkingView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ <com.android.car.ui.FocusArea
+ android:id="@+id/application_bar"
+ android:layout_width="@dimen/sidebar_width"
+ android:layout_height="match_parent"
+ android:gravity="top"
+ android:paddingTop="@dimen/suw_padding_3"
+ android:orientation="vertical">
+ <ImageView
+ android:id="@+id/back_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/round_button_background"
+ android:contentDescription="@string/back_button_content_description"
+ android:padding="@dimen/car_padding_2"
+ android:src="@drawable/car_ic_arrow_back"/>
+ <ImageView
+ android:id="@+id/close_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/round_button_background"
+ android:contentDescription="@string/close_button_content_description"
+ android:padding="@dimen/car_padding_2"
+ android:src="@drawable/car_ic_close"/>
+ </com.android.car.ui.FocusArea>
+ <LinearLayout
+ android:id="@+id/ultra_wide_content_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <include layout="@layout/progressbar"/>
+ <com.android.car.ui.FocusArea
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ <ViewStub
+ android:id="@+id/layout_content_stub"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </com.android.car.ui.FocusArea>
+ <include layout="@layout/rotary_action_bar"/>
+ </LinearLayout>
+ <FrameLayout
+ android:id="@+id/ultra_wide_space_filler"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@color/suw_color_background"/>
+</merge>
diff --git a/library/main/res/layout-w1760dp-land/split_nav_layout.xml b/library/main/res/layout-w1760dp-land/split_nav_layout.xml
new file mode 100644
index 0000000..c118c66
--- /dev/null
+++ b/library/main/res/layout-w1760dp-land/split_nav_layout.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <FrameLayout
+ android:id="@+id/application_bar"
+ android:layout_width="@dimen/sidebar_width"
+ android:layout_height="match_parent"
+ android:gravity="top"
+ android:paddingTop="@dimen/suw_padding_3">
+ <ImageView
+ android:id="@+id/back_button"
+ android:layout_width="@dimen/car_primary_icon_size"
+ android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/button_ripple_bg"
+ android:contentDescription="@string/back_button_content_description"
+ android:src="@drawable/car_ic_arrow_back"/>
+ <ImageView
+ android:id="@+id/close_button"
+ android:layout_width="@dimen/car_primary_icon_size"
+ android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/button_ripple_bg"
+ android:contentDescription="@string/close_button_content_description"
+ android:src="@drawable/car_ic_close"/>
+ </FrameLayout>
+ <LinearLayout
+ android:id="@+id/ultra_wide_content_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <include layout="@layout/progressbar"/>
+ <ViewStub
+ android:id="@+id/layout_content_stub"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+ <include layout="@layout/action_bar"/>
+ </LinearLayout>
+ <FrameLayout
+ android:id="@+id/ultra_wide_space_filler"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@color/suw_color_background"/>
+</merge>
diff --git a/library/main/res/layout/action_bar.xml b/library/main/res/layout/action_bar.xml
new file mode 100644
index 0000000..0920bb1
--- /dev/null
+++ b/library/main/res/layout/action_bar.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/button_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/actionbar_height"
+ android:paddingHorizontal="@dimen/suw_padding_7">
+ <ViewStub
+ android:id="@+id/primary_toolbar_button_stub"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:inflatedId="@+id/primary_toolbar_button"
+ android:layout="@layout/primary_button"/>
+ <ViewStub
+ android:id="@+id/secondary_toolbar_button_stub"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:inflatedId="@+id/secondary_toolbar_button"
+ android:layout="@layout/flat_button"/>
+</RelativeLayout> \ No newline at end of file
diff --git a/library/main/res/layout/car_setup_wizard_toolbar.xml b/library/main/res/layout/car_setup_wizard_toolbar.xml
index 5ae4e11..ff397d5 100644
--- a/library/main/res/layout/car_setup_wizard_toolbar.xml
+++ b/library/main/res/layout/car_setup_wizard_toolbar.xml
@@ -31,20 +31,22 @@
<ImageView
android:id="@+id/back_button"
- android:layout_width="@dimen/car_primary_icon_size"
- android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="center"
- android:background="@drawable/button_ripple_bg"
+ android:background="@drawable/round_button_background"
android:contentDescription="@string/back_button_content_description"
+ android:padding="@dimen/car_padding_2"
android:src="@drawable/car_ic_arrow_back"/>
<ImageView
android:id="@+id/close_button"
- android:layout_width="@dimen/car_primary_icon_size"
- android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="center"
- android:background="@drawable/button_ripple_bg"
+ android:background="@drawable/round_button_background"
android:contentDescription="@string/close_button_content_description"
+ android:padding="@dimen/car_padding_2"
android:src="@drawable/car_ic_close"/>
</FrameLayout>
diff --git a/library/main/res/layout/empty_fragment_frame_layout.xml b/library/main/res/layout/empty_fragment_frame_layout.xml
new file mode 100644
index 0000000..0ea8da7
--- /dev/null
+++ b/library/main/res/layout/empty_fragment_frame_layout.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/empty_fragment_frame_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" /> \ No newline at end of file
diff --git a/library/main/res/layout/progressbar.xml b/library/main/res/layout/progressbar.xml
new file mode 100644
index 0000000..3056662
--- /dev/null
+++ b/library/main/res/layout/progressbar.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/progress_bar"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:minHeight="0dp"
+ android:maxHeight="20dp"
+ android:indeterminateDrawable="@drawable/progress_indeterminate_horizontal_material_trimmed"
+ android:indeterminateTint="?android:attr/colorAccent"
+ android:indeterminateTintMode="src_in"/> \ No newline at end of file
diff --git a/library/main/res/layout/rotary_car_setup_wizard_layout.xml b/library/main/res/layout/rotary_car_setup_wizard_layout.xml
new file mode 100644
index 0000000..9e9819f
--- /dev/null
+++ b/library/main/res/layout/rotary_car_setup_wizard_layout.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <com.android.car.ui.FocusParkingView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <com.android.car.ui.FocusArea
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <include
+ android:id="@+id/application_bar"
+ layout="@layout/car_setup_wizard_toolbar"/>
+ </com.android.car.ui.FocusArea>
+
+ <com.android.car.ui.FocusArea
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ <ViewStub
+ android:id="@+id/layout_content_stub"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </com.android.car.ui.FocusArea>
+</merge>
diff --git a/library/main/res/layout/rotary_split_nav_layout.xml b/library/main/res/layout/rotary_split_nav_layout.xml
new file mode 100644
index 0000000..1a8a004
--- /dev/null
+++ b/library/main/res/layout/rotary_split_nav_layout.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <com.android.car.ui.FocusParkingView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <com.android.car.ui.FocusArea
+ android:id="@+id/application_bar"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/suw_padding_8"
+ android:paddingStart="@dimen/navbar_padding_start"
+ android:gravity="start">
+
+ <ImageView
+ android:id="@+id/back_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/round_button_background"
+ android:contentDescription="@string/back_button_content_description"
+ android:padding="@dimen/car_padding_2"
+ android:src="@drawable/car_ic_arrow_back"/>
+
+ <ImageView
+ android:id="@+id/close_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/round_button_background"
+ android:contentDescription="@string/close_button_content_description"
+ android:padding="@dimen/car_padding_2"
+ android:src="@drawable/car_ic_close"/>
+ </com.android.car.ui.FocusArea>
+
+ <include layout="@layout/progressbar"/>
+
+ <com.android.car.ui.FocusArea
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ <ViewStub
+ android:id="@+id/layout_content_stub"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </com.android.car.ui.FocusArea>
+
+ <com.android.car.ui.FocusArea
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <include layout="@layout/action_bar"/>
+ </com.android.car.ui.FocusArea>
+</merge> \ No newline at end of file
diff --git a/library/main/res/layout/split_nav_compat_activity.xml b/library/main/res/layout/split_nav_compat_activity.xml
new file mode 100644
index 0000000..ee4b0eb
--- /dev/null
+++ b/library/main/res/layout/split_nav_compat_activity.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<com.android.car.setupwizardlib.CarSetupWizardCompatLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/car_setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:showBackButton="true"
+ app:showPrimaryToolbarButton="true"
+ app:primaryToolbarButtonEnabled="true"
+ app:supportsSplitNavLayout="true"
+ app:supportsRotaryControl="true"/> \ No newline at end of file
diff --git a/library/main/res/layout/split_nav_design_activity.xml b/library/main/res/layout/split_nav_design_activity.xml
new file mode 100644
index 0000000..19454c6
--- /dev/null
+++ b/library/main/res/layout/split_nav_design_activity.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<com.android.car.setupwizardlib.CarSetupWizardDesignLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/car_setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:showBackButton="true"
+ app:showPrimaryToolbarButton="true"
+ app:primaryToolbarButtonEnabled="true"
+ app:supportsSplitNavLayout="true"
+ app:supportsRotaryControl="true"/>
diff --git a/library/main/res/layout/split_nav_layout.xml b/library/main/res/layout/split_nav_layout.xml
new file mode 100644
index 0000000..03ee676
--- /dev/null
+++ b/library/main/res/layout/split_nav_layout.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <FrameLayout
+ android:id="@+id/application_bar"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/suw_padding_8"
+ android:paddingStart="@dimen/navbar_padding_start"
+ android:gravity="start">
+
+ <ImageView
+ android:id="@+id/back_button"
+ android:layout_width="@dimen/car_primary_icon_size"
+ android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/button_ripple_bg"
+ android:contentDescription="@string/back_button_content_description"
+ android:src="@drawable/car_ic_arrow_back"/>
+
+ <ImageView
+ android:id="@+id/close_button"
+ android:layout_width="@dimen/car_primary_icon_size"
+ android:layout_height="@dimen/car_primary_icon_size"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/button_ripple_bg"
+ android:contentDescription="@string/close_button_content_description"
+ android:src="@drawable/car_ic_close"/>
+ </FrameLayout>
+
+ <include layout="@layout/progressbar"/>
+
+ <ViewStub
+ android:id="@+id/layout_content_stub"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <include layout="@layout/action_bar"/>
+</merge> \ No newline at end of file
diff --git a/library/main/res/values/attrs.xml b/library/main/res/values/attrs.xml
index 31d2f5b..d5fd07b 100644
--- a/library/main/res/values/attrs.xml
+++ b/library/main/res/values/attrs.xml
@@ -90,6 +90,11 @@
of the progress bar -->
<attr name="showProgressBar"/>
<attr name="indeterminateProgressBar"/>
+
+ <!-- Attributes related to the split nav layout -->
+ <attr name="supportsSplitNavLayout" format="boolean"/>
+ <!-- Attributes related to the rotary support -->
+ <attr name="supportsRotaryControl" format="boolean"/>
</declare-styleable>
</resources>
diff --git a/library/main/res/values/colors.xml b/library/main/res/values/colors.xml
index a3df84d..77a2748 100644
--- a/library/main/res/values/colors.xml
+++ b/library/main/res/values/colors.xml
@@ -36,4 +36,12 @@
<color name="suw_color_divider">#3C4043</color>
<!-- Material grey900 -->
<color name="suw_color_background">#202124</color>
+ <!-- Material grey868 -->
+ <color name="suw_color_split_nav_toolbar_background">#282B2D</color>
+
+ <!-- Rotary focus highlight -->
+ <color name="suw_rotary_focus_stroke_color">#94CBFF</color>
+ <color name="suw_rotary_focus_fill_color">#3D94CBFF</color>
+ <color name="suw_rotary_focus_pressed_stroke_color">#94CBFF</color>
+ <color name="suw_rotary_focus_pressed_fill_color">#8A94CBFF</color>
</resources>
diff --git a/library/main/res/values/dimens.xml b/library/main/res/values/dimens.xml
index db6c833..6c2b322 100644
--- a/library/main/res/values/dimens.xml
+++ b/library/main/res/values/dimens.xml
@@ -27,4 +27,12 @@
<dimen name="suw_page_margin_horizontal">112dp</dimen>
<!-- The column inner padding of a two-column layout. N/A in portrait -->
<dimen name="suw_column_inner_padding_horizontal">0dp</dimen>
+
+ <dimen name="sidebar_width">@dimen/suw_padding_8</dimen>
+ <dimen name="navbar_padding_start">10dp</dimen>
+ <dimen name="actionbar_height">@dimen/suw_padding_9</dimen>
+
+ <!-- Rotary focus highlight -->
+ <dimen name="suw_rotary_focus_stroke_width">8dp</dimen>
+ <dimen name="suw_rotary_focus_pressed_stroke_width">4dp</dimen>
</resources> \ No newline at end of file
diff --git a/library/main/res/values/styles.xml b/library/main/res/values/styles.xml
index 6ab739d..8155505 100644
--- a/library/main/res/values/styles.xml
+++ b/library/main/res/values/styles.xml
@@ -18,11 +18,13 @@
<style name="Widget.Car.SetupWizard.Button" parent="Widget.Car.Button.DarkText">
<item name="android:fontFamily">@font/sans_medium</item>
<item name="android:textAllCaps">false</item>
+ <item name="android:background">@drawable/primary_button_background</item>
</style>
<style name="Widget.Car.SetupWizard.Button.Borderless.Colored"
parent="Widget.Car.Button.Borderless.Colored">
<item name="android:fontFamily">@font/sans_medium</item>
<item name="android:textAllCaps">false</item>
+ <item name="android:background">@drawable/flat_button_background</item>
</style>
</resources>
diff --git a/library/main/res/values/themes.xml b/library/main/res/values/themes.xml
index b24738a..ac71ded 100644
--- a/library/main/res/values/themes.xml
+++ b/library/main/res/values/themes.xml
@@ -23,7 +23,13 @@
<item name="android:colorControlNormal">?android:attr/colorAccent</item>
<item name="android:colorControlActivated">?android:attr/colorAccent</item>
<item name="android:buttonStyle">@style/Widget.Car.SetupWizard.Button</item>
- <item name="android:borderlessButtonStyle">@style/Widget.Car.SetupWizard.Button.Borderless.Colored</item>
+ <item name="buttonStyle">@style/Widget.Car.SetupWizard.Button</item>
+ <item name="materialButtonStyle">@style/Widget.Car.SetupWizard.Button</item>
+ <item name="android:borderlessButtonStyle">
+ @style/Widget.Car.SetupWizard.Button.Borderless.Colored
+ </item>
+ <item name="borderlessButtonStyle">@style/Widget.Car.SetupWizard.Button.Borderless.Colored
+ </item>
</style>
<style name="Theme.Car.SetupWizard.NoActionBar.Accent" parent="Theme.Car.SetupWizard.NoActionBar">
diff --git a/library/main/src/com/android/car/setupwizardlib/BaseCompatActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseCompatActivity.java
index c8bcf4b..5cca557 100644
--- a/library/main/src/com/android/car/setupwizardlib/BaseCompatActivity.java
+++ b/library/main/src/com/android/car/setupwizardlib/BaseCompatActivity.java
@@ -24,7 +24,8 @@ public class BaseCompatActivity extends BaseSetupWizardActivity {
@Override
@LayoutRes
int getLayout() {
- return R.layout.base_compat_activity;
+ return isSplitNavLayoutSupported()
+ ? R.layout.split_nav_compat_activity : R.layout.base_compat_activity;
}
@Override
diff --git a/library/main/src/com/android/car/setupwizardlib/BaseDesignActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseDesignActivity.java
index a7288b5..5650f71 100644
--- a/library/main/src/com/android/car/setupwizardlib/BaseDesignActivity.java
+++ b/library/main/src/com/android/car/setupwizardlib/BaseDesignActivity.java
@@ -24,7 +24,8 @@ public class BaseDesignActivity extends BaseSetupWizardActivity {
@Override
@LayoutRes
int getLayout() {
- return R.layout.base_design_activity;
+ return isSplitNavLayoutSupported()
+ ? R.layout.split_nav_design_activity : R.layout.base_design_activity;
}
@Override
diff --git a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
index 36caae0..f8d9342 100644
--- a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
+++ b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
@@ -19,7 +19,9 @@ package com.android.car.setupwizardlib;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.View;
+import android.view.ViewStub;
import androidx.annotation.CallSuper;
import androidx.annotation.LayoutRes;
@@ -48,6 +50,8 @@ import com.android.car.setupwizardlib.util.CarWizardManagerHelper;
* component attributes
*/
abstract class BaseSetupWizardActivity extends FragmentActivity {
+ private static final String TAG = BaseSetupWizardActivity.class.getSimpleName();
+
@VisibleForTesting
static final String CONTENT_FRAGMENT_TAG = "CONTENT_FRAGMENT_TAG";
/**
@@ -91,13 +95,9 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
mCarSetupWizardLayout = findViewById(R.id.car_setup_wizard_layout);
- mCarSetupWizardLayout.setBackButtonListener(v -> {
- if (!handleBackButton()) {
- finish();
- }
- });
+ mCarSetupWizardLayout.setBackButtonListener(v -> handleBackButtonEvent());
- mCarSetupWizardLayout.setCloseButtonListener(v-> handleCloseButton());
+ mCarSetupWizardLayout.setCloseButtonListener(v -> handleCloseButton());
resetPrimaryToolbarButtonOnClickListener();
resetSecondaryToolbarButtonOnClickListener();
@@ -176,8 +176,9 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
@CallSuper
protected void setContentFragmentWithBackstack(Fragment fragment) {
if (mAllowFragmentCommits) {
+ inflateEmptyFragmentFrameLayout();
getSupportFragmentManager().beginTransaction()
- .replace(R.id.car_setup_wizard_layout, fragment, CONTENT_FRAGMENT_TAG)
+ .replace(getFragmentContainerViewId(), fragment, CONTENT_FRAGMENT_TAG)
.addToBackStack(null)
.commit();
getSupportFragmentManager().executePendingTransactions();
@@ -199,13 +200,14 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
@CallSuper
protected void setContentFragment(Fragment fragment) {
if (mAllowFragmentCommits) {
+ inflateEmptyFragmentFrameLayout();
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(
android.R.animator.fade_in,
android.R.animator.fade_out,
android.R.animator.fade_in,
android.R.animator.fade_out)
- .replace(R.id.car_setup_wizard_layout, fragment, CONTENT_FRAGMENT_TAG)
+ .replace(getFragmentContainerViewId(), fragment, CONTENT_FRAGMENT_TAG)
.commitNow();
onContentFragmentSet(getContentFragment());
}
@@ -242,10 +244,25 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
*/
@CallSuper
protected View setContentLayout(@LayoutRes int id) {
+ ViewStub viewStub = findViewById(R.id.layout_content_stub);
+ if (viewStub != null) {
+ viewStub.setLayoutResource(id);
+ return viewStub.inflate();
+ }
return getLayoutInflater().inflate(id, mCarSetupWizardLayout);
}
/**
+ * Method used when back button is pressed, if the back button wasn't handled by the activity
+ * finish() will be called.
+ */
+ private void handleBackButtonEvent() {
+ if (!handleBackButton()) {
+ finish();
+ }
+ }
+
+ /**
* Method to be overwritten by subclasses wanting to implement their own back behavior.
* Default behavior is to pop a fragment off of the backstack if one exists, otherwise call
* finish()
@@ -256,6 +273,16 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
return popBackStackImmediate();
}
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ && event.getAction() == KeyEvent.ACTION_UP) {
+ handleBackButtonEvent();
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
/**
* Method to be overwritten by subclasses wanting to implement their own close behavior.
* Default behavior is finishAction.
@@ -486,6 +513,10 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
mCarSetupWizardLayout.setProgressBarVisible(visible);
}
+ protected boolean isSplitNavLayoutSupported() {
+ return false;
+ }
+
private void launchNextAction(int resultCode, Intent data, boolean forResult) {
if (resultCode == RESULT_CANCELED) {
throw new IllegalArgumentException("Cannot call nextAction with RESULT_CANCELED");
@@ -509,6 +540,30 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
}
@VisibleForTesting
+ int getFragmentContainerViewId() {
+ // Check if the inflated frame layout is still available. Add the fragment to frame
+ // layout only if it's available. Otherwise, fall back to default layout to attach
+ // fragment. Note that frame layout might not be available if hosting activity inflated
+ // viewStub already with other views than before calling setFragmentContent().
+ View frameLayout = findViewById(R.id.empty_fragment_frame_layout);
+ int containerViewId = frameLayout == null ? R.id.car_setup_wizard_layout :
+ R.id.empty_fragment_frame_layout;
+ Log.v(TAG, "fragmentContainerViewId: "
+ + getResources().getResourceEntryName(containerViewId));
+ return containerViewId;
+
+ }
+
+ @VisibleForTesting
+ void inflateEmptyFragmentFrameLayout() {
+ ViewStub viewStub = findViewById(R.id.layout_content_stub);
+ if (viewStub != null) {
+ viewStub.setLayoutResource(R.layout.empty_fragment_frame_layout);
+ viewStub.inflate();
+ }
+ }
+
+ @VisibleForTesting
boolean getAllowFragmentCommits() {
return mAllowFragmentCommits;
}
diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java
index 715315a..4fd1808 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java
@@ -18,6 +18,7 @@ package com.android.car.setupwizardlib;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.Typeface;
@@ -39,14 +40,12 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
-
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
-
import com.android.car.setupwizardlib.partner.PartnerConfig;
import com.android.car.setupwizardlib.partner.PartnerConfigHelper;
-
+import com.android.car.setupwizardlib.util.FeatureResolver;
import java.util.Locale;
import java.util.Objects;
@@ -56,17 +55,20 @@ import java.util.Objects;
* done through methods provided by this class unless that is not possible so as to keep the state
* internally consistent.
*/
-class CarSetupWizardBaseLayout extends LinearLayout {
+class CarSetupWizardBaseLayout extends LinearLayout implements CarSetupWizardLayoutInterface {
private static final String TAG = CarSetupWizardBaseLayout.class.getSimpleName();
private static final int INVALID_COLOR = 0;
// For mirroring an image
private static final float IMAGE_MIRROR_ROTATION = 180.0f;
+ private static final float MIN_ULTRA_WIDE_CONTENT_WIDTH = 1240.0f;
private View mBackButton;
private View mCloseButton;
private View mTitleBar;
private TextView mToolbarTitle;
private PartnerConfigHelper mPartnerConfigHelper;
+ private boolean mSupportsSplitNavLayout;
+ private boolean mSupportsRotaryControl;
/* <p>The Primary Toolbar Button should always be used when there is only a single action that
* moves the wizard to the next screen (e.g. Only need a 'Skip' button).
@@ -95,7 +97,7 @@ class CarSetupWizardBaseLayout extends LinearLayout {
}
CarSetupWizardBaseLayout(Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
+ int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@@ -104,7 +106,7 @@ class CarSetupWizardBaseLayout extends LinearLayout {
* the custom views that can be set by the user (e.g. back button, continue button).
*/
CarSetupWizardBaseLayout(Context context, @Nullable AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
+ int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mPartnerConfigHelper = PartnerConfigHelper.get(context);
@@ -164,12 +166,19 @@ class CarSetupWizardBaseLayout extends LinearLayout {
R.styleable.CarSetupWizardBaseLayout_showProgressBar, false);
indeterminateProgressBar = attrArray.getBoolean(
R.styleable.CarSetupWizardBaseLayout_indeterminateProgressBar, true);
+ mSupportsSplitNavLayout = attrArray.getBoolean(
+ R.styleable.CarSetupWizardBaseLayout_supportsSplitNavLayout, false);
+ mSupportsRotaryControl = attrArray.getBoolean(
+ R.styleable.CarSetupWizardBaseLayout_supportsRotaryControl, false);
} finally {
attrArray.recycle();
}
LayoutInflater inflater = LayoutInflater.from(getContext());
- inflater.inflate(R.layout.car_setup_wizard_layout, this);
+ inflater.inflate(getLayoutResourceId(), this);
+
+ maybeSetUltraWideScreenContentWidth();
+
View toolbar = findViewById(R.id.application_bar);
// The toolbar will not be mirrored in RTL
toolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
@@ -206,10 +215,15 @@ class CarSetupWizardBaseLayout extends LinearLayout {
// Se the title bar.
setTitleBar(findViewById(R.id.application_bar));
- int toolbarBgColor =
- mPartnerConfigHelper.getColor(getContext(), PartnerConfig.CONFIG_TOOLBAR_BG_COLOR);
- if (toolbarBgColor != 0) {
- mTitleBar.setBackgroundColor(toolbarBgColor);
+ if (isSplitNavLayoutUsed()) {
+ mTitleBar.setBackgroundColor(getResources()
+ .getColor(R.color.suw_color_split_nav_toolbar_background, null));
+ } else {
+ int toolbarBgColor = mPartnerConfigHelper.getColor(
+ getContext(), PartnerConfig.CONFIG_TOOLBAR_BG_COLOR);
+ if (toolbarBgColor != 0) {
+ mTitleBar.setBackgroundColor(toolbarBgColor);
+ }
}
// Set the toolbar title visibility and text based on the custom attributes.
@@ -264,7 +278,25 @@ class CarSetupWizardBaseLayout extends LinearLayout {
initDivider();
// Set orientation programmatically since the inflated layout uses <merge>
- setOrientation(LinearLayout.VERTICAL);
+ if (isSplitNavLayoutUsed() && getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_LANDSCAPE) {
+ setOrientation(LinearLayout.HORIZONTAL);
+ // The vertical bar will not be mirrored in RTL
+ setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+
+ View contentContainer = getContentContainer();
+ if (contentContainer != null) {
+ // The content should be mirrored in RTL
+ contentContainer.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
+ }
+ View actionBar = findViewById(R.id.button_container);
+ if (actionBar != null) {
+ // The action bar will not be mirrored in RTL
+ actionBar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+ }
+ } else {
+ setOrientation(LinearLayout.VERTICAL);
+ }
}
/**
@@ -400,6 +432,9 @@ class CarSetupWizardBaseLayout extends LinearLayout {
* Sets the header title visibility to given value.
*/
public void setToolbarTitleVisible(boolean visible) {
+ if (mToolbarTitle == null) {
+ return;
+ }
setViewVisible(mToolbarTitle, visible);
}
@@ -407,6 +442,9 @@ class CarSetupWizardBaseLayout extends LinearLayout {
* Sets the header title text to the provided text.
*/
public void setToolbarTitleText(String text) {
+ if (mToolbarTitle == null) {
+ return;
+ }
mToolbarTitle.setText(text);
}
@@ -414,6 +452,9 @@ class CarSetupWizardBaseLayout extends LinearLayout {
* Sets the style for the toolbar title.
*/
public void setToolbarTitleStyle(@StyleRes int style) {
+ if (mToolbarTitle == null) {
+ return;
+ }
mToolbarTitle.setTextAppearance(style);
}
@@ -557,28 +598,109 @@ class CarSetupWizardBaseLayout extends LinearLayout {
return mProgressBar;
}
- /**
- * Sets the progress bar visibility to the given visibility.
- */
+ @Override
public void setProgressBarVisible(boolean visible) {
setViewVisible(mProgressBar, visible);
}
- /**
- * Sets the progress bar indeterminate/determinate state.
- */
+ @Override
public void setProgressBarIndeterminate(boolean indeterminate) {
mProgressBar.setIndeterminate(indeterminate);
}
- /**
- * Sets the progress bar's progress.
- */
+ @Override
public void setProgressBarProgress(int progress) {
setProgressBarIndeterminate(false);
mProgressBar.setProgress(progress);
}
+ @Override
+ public Button getPrimaryActionButton() {
+ return getPrimaryToolbarButton();
+ }
+
+ @Override
+ public void setPrimaryActionButtonVisible(boolean visible) {
+ setPrimaryToolbarButtonVisible(visible);
+ }
+
+ @Override
+ public void setPrimaryActionButtonEnabled(boolean enabled) {
+ setPrimaryToolbarButtonEnabled(enabled);
+ }
+
+ @Override
+ public void setPrimaryActionButtonText(String text) {
+ setPrimaryToolbarButtonText(text);
+ }
+
+ @Override
+ public void setPrimaryActionButtonListener(@Nullable View.OnClickListener listener) {
+ setPrimaryToolbarButtonListener(listener);
+ }
+
+ @Override
+ public void setPrimaryActionButtonFlat(boolean isFlat) {
+ setPrimaryToolbarButtonFlat(isFlat);
+ }
+
+ @Override
+ public boolean isPrimaryActionButtonFlat() {
+ return getPrimaryToolbarButtonFlat();
+ }
+
+ @Override
+ public Button getSecondaryActionButton() {
+ return getSecondaryToolbarButton();
+ }
+
+ @Override
+ public void setSecondaryActionButtonVisible(boolean visible) {
+ setSecondaryToolbarButtonVisible(visible);
+ }
+
+ @Override
+ public void setSecondaryActionButtonEnabled(boolean enabled) {
+ setSecondaryToolbarButtonEnabled(enabled);
+ }
+
+ @Override
+ public void setSecondaryActionButtonText(String text) {
+ setSecondaryToolbarButtonText(text);
+ }
+
+ @Override
+ public void setSecondaryActionButtonListener(@Nullable View.OnClickListener listener) {
+ setSecondaryToolbarButtonListener(listener);
+ }
+
+ /**
+ * Returns whether split-nav layout is currently being used. Do not use this API to determine
+ * whether content ViewStub should be inflated. Use {@code getContentViewStub} for that purpose.
+ */
+ public boolean isSplitNavLayoutUsed() {
+ boolean isSplitNavLayoutEnabled = FeatureResolver.get(getContext())
+ .isSplitNavLayoutFeatureEnabled();
+ return mSupportsSplitNavLayout && isSplitNavLayoutEnabled;
+ }
+
+ /**
+ * Returns the content ViewStub of the split-nav layout.
+ *
+ * @deprecated Use {@code getContentViewStub}.
+ */
+ @Deprecated
+ public ViewStub getSplitNavContentViewStub() {
+ return findViewById(R.id.layout_content_stub);
+ }
+
+ /**
+ * Returns the content ViewStub when split-nav layout is used or rotary control is supported
+ */
+ public ViewStub getContentViewStub() {
+ return findViewById(R.id.layout_content_stub);
+ }
+
/**
* Sets the locale to be used for rendering.
*/
@@ -588,8 +710,10 @@ class CarSetupWizardBaseLayout extends LinearLayout {
}
int direction = TextUtils.getLayoutDirectionFromLocale(locale);
- mToolbarTitle.setTextLocale(locale);
- mToolbarTitle.setLayoutDirection(direction);
+ if (mToolbarTitle != null) {
+ mToolbarTitle.setTextLocale(locale);
+ mToolbarTitle.setLayoutDirection(direction);
+ }
mPrimaryToolbarButton.setTextLocale(locale);
mPrimaryToolbarButton.setLayoutDirection(direction);
@@ -641,7 +765,9 @@ class CarSetupWizardBaseLayout extends LinearLayout {
}
}
- /** Sets button text color using partner overlay if exists */
+ /**
+ * Sets button text color using partner overlay if exists
+ */
@VisibleForTesting
void setButtonTextColor(TextView button, PartnerConfig config) {
ColorStateList colorStateList =
@@ -669,7 +795,9 @@ class CarSetupWizardBaseLayout extends LinearLayout {
}
}
- /** Sets button background color using partner overlay if exists */
+ /**
+ * Sets button background color using partner overlay if exists
+ */
@VisibleForTesting
void setBackgroundColor(View button, PartnerConfig config) {
ColorStateList color = mPartnerConfigHelper.getColorStateList(getContext(), config);
@@ -678,7 +806,9 @@ class CarSetupWizardBaseLayout extends LinearLayout {
}
}
- /** Sets button text size using partner overlay if exists */
+ /**
+ * Sets button text size using partner overlay if exists
+ */
@VisibleForTesting
void setButtonTextSize(TextView button) {
float dimension = mPartnerConfigHelper.getDimension(
@@ -692,13 +822,13 @@ class CarSetupWizardBaseLayout extends LinearLayout {
@VisibleForTesting
boolean shouldMirrorNavIcons() {
return getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
- && mPartnerConfigHelper.getBoolean(
- getContext(),
- PartnerConfig.CONFIG_TOOLBAR_NAV_ICON_MIRRORING_IN_RTL,
- true);
+ && mPartnerConfigHelper.getBoolean(
+ getContext(), PartnerConfig.CONFIG_TOOLBAR_NAV_ICON_MIRRORING_IN_RTL, true);
}
- /** Sets button type face with partner overlay if exists */
+ /**
+ * Sets button type face with partner overlay if exists
+ */
private void setButtonTypeFace(TextView button) {
String fontFamily = mPartnerConfigHelper.getString(
getContext(),
@@ -716,7 +846,9 @@ class CarSetupWizardBaseLayout extends LinearLayout {
button.setTypeface(typeface);
}
- /** Sets button radius using partner overlay if exists */
+ /**
+ * Sets button radius using partner overlay if exists
+ */
private void setButtonRadius(Button button) {
float radius = mPartnerConfigHelper.getDimension(
getContext(),
@@ -760,8 +892,23 @@ class CarSetupWizardBaseLayout extends LinearLayout {
setButtonTextColor(primaryButton, textColorConfig);
}
+ private int getLayoutResourceId() {
+ if (isSplitNavLayoutUsed()) {
+ return mSupportsRotaryControl
+ ? R.layout.rotary_split_nav_layout
+ : R.layout.split_nav_layout;
+ }
+
+ return mSupportsRotaryControl
+ ? R.layout.rotary_car_setup_wizard_layout
+ : R.layout.car_setup_wizard_layout;
+ }
+
private void initDivider() {
mDivider = findViewById(R.id.divider);
+ if (mDivider == null) {
+ return;
+ }
float dividerHeight = mPartnerConfigHelper.getDimension(
getContext(),
PartnerConfig.CONFIG_TOOLBAR_DIVIDER_LINE_WEIGHT);
@@ -791,7 +938,9 @@ class CarSetupWizardBaseLayout extends LinearLayout {
if (drawable instanceof InsetDrawable) {
return getGradientDrawableFromInsetDrawable((InsetDrawable) drawable);
}
- return (GradientDrawable) drawable;
+ if (drawable instanceof GradientDrawable) {
+ return (GradientDrawable) drawable;
+ }
}
return null;
@@ -803,4 +952,53 @@ class CarSetupWizardBaseLayout extends LinearLayout {
}
return null;
}
+
+ private void maybeSetUltraWideScreenContentWidth() {
+ View contentContainer = findViewById(R.id.ultra_wide_content_container);
+ if (contentContainer == null) {
+ return;
+ }
+
+ float configurableContentWidth = mPartnerConfigHelper.getDimension(
+ getContext(),
+ PartnerConfig.CONFIG_ULTRA_WIDE_SCREEN_CONTENT_WIDTH);
+
+ float pxMinWidth = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ MIN_ULTRA_WIDE_CONTENT_WIDTH,
+ getResources().getDisplayMetrics());
+
+ if (configurableContentWidth >= pxMinWidth) {
+ ViewGroup.LayoutParams layoutParams = contentContainer.getLayoutParams();
+ layoutParams.width = (int) configurableContentWidth;
+ Log.d(TAG, String.format("Applying content width %f px", configurableContentWidth));
+ contentContainer.setLayoutParams(layoutParams);
+ } else {
+ if (configurableContentWidth != 0) {
+ Log.w(TAG, String.format("The minimum ultra wide screen content width is %d dp",
+ (int) MIN_ULTRA_WIDE_CONTENT_WIDTH));
+ }
+
+ LinearLayout.LayoutParams contentParams = new LinearLayout.LayoutParams(
+ 0, LayoutParams.MATCH_PARENT);
+ contentParams.weight = 1;
+ contentContainer.setLayoutParams(contentParams);
+
+ LinearLayout.LayoutParams fillerParams = new LinearLayout.LayoutParams(
+ 0, LayoutParams.MATCH_PARENT);
+ fillerParams.weight = 0;
+ View filler = findViewById(R.id.ultra_wide_space_filler);
+ filler.setLayoutParams(fillerParams);
+ }
+ }
+
+ private View getContentContainer() {
+ View contentContainer = findViewById(R.id.content_container);
+ if (contentContainer == null) {
+ // Try ultra-wide container
+ return findViewById(R.id.ultra_wide_content_container);
+
+ }
+ return contentContainer;
+ }
}
diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java
index f5191cc..72f4f1b 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java
@@ -18,7 +18,6 @@ package com.android.car.setupwizardlib;
import android.content.Context;
import android.util.AttributeSet;
-
import androidx.annotation.Nullable;
/**
@@ -43,5 +42,7 @@ public class CarSetupWizardCompatLayout extends CarSetupWizardBaseLayout {
public CarSetupWizardCompatLayout(Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+
+ setBackgroundColor(getResources().getColor(R.color.suw_color_background, null));
}
}
diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java
index 92269f0..c0a1831 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java
@@ -18,9 +18,7 @@ package com.android.car.setupwizardlib;
import android.content.Context;
import android.util.AttributeSet;
-
import androidx.annotation.Nullable;
-
import com.android.car.setupwizardlib.partner.PartnerConfig;
import com.android.car.setupwizardlib.partner.PartnerConfigHelper;
diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java
index 19a1923..67bb795 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java
@@ -38,14 +38,11 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
-
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
-
import com.android.car.setupwizardlib.partner.PartnerConfig;
import com.android.car.setupwizardlib.partner.PartnerConfigHelper;
-
import java.util.Locale;
import java.util.Objects;
diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayoutInterface.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayoutInterface.java
new file mode 100644
index 0000000..7126560
--- /dev/null
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayoutInterface.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 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.car.setupwizardlib;
+
+import android.view.View;
+import android.widget.Button;
+import androidx.annotation.Nullable;
+
+/**
+ * The interface defines the functionality of the layouts used in CarSetupWizard. It
+ * makes it easy to switch to a different layout.
+ */
+public interface CarSetupWizardLayoutInterface {
+
+ /** Returns the primary action button. */
+ Button getPrimaryActionButton();
+
+ /** Sets whether the primary action button is visible. */
+ void setPrimaryActionButtonVisible(boolean visible);
+
+ /** Sets whether the primary action button is enabled. */
+ void setPrimaryActionButtonEnabled(boolean enabled);
+
+ /** Sets the text of the primary action button. */
+ void setPrimaryActionButtonText(String text);
+
+ /**
+ * Sets the onClick listener of the primary action button.
+ *
+ * @param listener the listener to be set. When it's null, the previously set listener will be
+ * removed
+ */
+ void setPrimaryActionButtonListener(@Nullable View.OnClickListener listener);
+
+ /** Sets whether the primary action button is flat which means it does not have a background. */
+ void setPrimaryActionButtonFlat(boolean isFlat);
+
+ /** Returns whether the primary action button is flat. */
+ boolean isPrimaryActionButtonFlat();
+
+ /** Returns the secondary action button. */
+ Button getSecondaryActionButton();
+
+ /** Sets whether the secondary action button is visible. */
+ void setSecondaryActionButtonVisible(boolean visible);
+
+ /** Sets whether the secondary action button is enabled. */
+ void setSecondaryActionButtonEnabled(boolean enabled);
+
+ /** Sets the text of the secondary action button. */
+ void setSecondaryActionButtonText(String text);
+
+ /**
+ * Sets the onClick listener of the secondary action button.
+ *
+ * @param listener the listener to be set. When it's null, the previously set listener will be
+ * removed
+ */
+ void setSecondaryActionButtonListener(@Nullable View.OnClickListener listener);
+
+ /** Sets whether the progress bar is visible. */
+ void setProgressBarVisible(boolean visible);
+
+ /** Sets whether the progress bar is indeterminate. */
+ void setProgressBarIndeterminate(boolean indeterminate);
+
+ /** Sets the progress bar's progress. */
+ void setProgressBarProgress(int progress);
+}
diff --git a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java
index 54d1e6e..2ee8d07 100644
--- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java
+++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java
@@ -83,7 +83,10 @@ public enum PartnerConfig {
PartnerConfigKey.KEY_LOADING_INDICATOR_LINE_WEIGHT, ResourceType.DIMENSION),
CONFIG_LAYOUT_BG_COLOR(
- PartnerConfigKey.KEY_LAYOUT_BG_COLOR, ResourceType.COLOR);
+ PartnerConfigKey.KEY_LAYOUT_BG_COLOR, ResourceType.COLOR),
+
+ CONFIG_ULTRA_WIDE_SCREEN_CONTENT_WIDTH(
+ PartnerConfigKey.KEY_ULTRA_WIDE_SCREEN_CONTENT_WIDTH, ResourceType.DIMENSION);
public enum ResourceType {
COLOR,
diff --git a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigHelper.java b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigHelper.java
index dfb134f..093961b 100644
--- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigHelper.java
+++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigHelper.java
@@ -27,12 +27,10 @@ import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.util.TypedValue;
-
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-
import java.util.EnumMap;
/** The helper reads and caches the partner configurations from Car Setup Wizard. */
diff --git a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java
index 7f9dadd..e7800d1 100644
--- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java
+++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java
@@ -44,7 +44,8 @@ import java.lang.annotation.RetentionPolicy;
PartnerConfigKey.KEY_TOOLBAR_DIVIDER_LINE_WEIGHT,
PartnerConfigKey.KEY_LOADING_INDICATOR_COLOR,
PartnerConfigKey.KEY_LOADING_INDICATOR_LINE_WEIGHT,
- PartnerConfigKey.KEY_LAYOUT_BG_COLOR
+ PartnerConfigKey.KEY_LAYOUT_BG_COLOR,
+ PartnerConfigKey.KEY_ULTRA_WIDE_SCREEN_CONTENT_WIDTH
})
/** Resource names that can be customized by partner overlay APK. */
@@ -96,4 +97,6 @@ public @interface PartnerConfigKey {
String KEY_LOADING_INDICATOR_LINE_WEIGHT = "suw_compat_loading_indicator_line_weight";
String KEY_LAYOUT_BG_COLOR = "suw_design_layout_bg_color";
+
+ String KEY_ULTRA_WIDE_SCREEN_CONTENT_WIDTH = "suw_compat_ultra_wide_screen_content_width";
}
diff --git a/library/main/src/com/android/car/setupwizardlib/partner/ResourceEntry.java b/library/main/src/com/android/car/setupwizardlib/partner/ResourceEntry.java
index 6d5d39b..456f1e6 100644
--- a/library/main/src/com/android/car/setupwizardlib/partner/ResourceEntry.java
+++ b/library/main/src/com/android/car/setupwizardlib/partner/ResourceEntry.java
@@ -18,7 +18,6 @@ package com.android.car.setupwizardlib.partner;
import android.content.pm.PackageManager;
import android.os.Bundle;
-
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
diff --git a/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java b/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java
index 2dfb04b..84842f3 100644
--- a/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java
+++ b/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java
@@ -27,9 +27,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
-
import androidx.annotation.Nullable;
-
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -151,11 +149,13 @@ public class PartnerSummaryActionsCollector {
String completedDescription =
summaryStateBundle.getString(EXTRA_SUMMARY_COMPLETED_DESCRIPTION, description);
+ SummaryActionState completeState = completed
+ ? SummaryActionState.COMPLETED : SummaryActionState.NOT_COMPLETED;
return new SummaryAction(
title,
description,
requiresNetwork,
- completed,
+ completeState,
priority,
scriptUri,
hasUnfinishedDependency,
diff --git a/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java b/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java
index 6f9e626..55d71d7 100644
--- a/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java
+++ b/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java
@@ -28,7 +28,7 @@ public class SummaryAction implements Comparable<SummaryAction> {
public final int priority;
public final boolean hasUnfinishedDependency;
public final String dependencyDescription;
- public final boolean completed;
+ public final SummaryActionState completeState;
public final String iconResourceName;
public final String completedDescription;
@@ -36,7 +36,7 @@ public class SummaryAction implements Comparable<SummaryAction> {
String actionTitle,
String actionDescription,
boolean requiresNetwork,
- boolean completed,
+ SummaryActionState completeState,
int priority,
String scriptUri,
boolean hasUnfinishedDependency,
@@ -46,7 +46,7 @@ public class SummaryAction implements Comparable<SummaryAction> {
this.actionTitle = actionTitle;
this.actionDescription = actionDescription;
this.requiresNetwork = requiresNetwork;
- this.completed = completed;
+ this.completeState = completeState;
this.priority = priority;
this.scriptUri = scriptUri;
this.hasUnfinishedDependency = hasUnfinishedDependency;
@@ -55,6 +55,11 @@ public class SummaryAction implements Comparable<SummaryAction> {
this.completedDescription = completedDescription;
}
+ /** Returns {@code true} if the action is completed. */
+ public boolean isCompleted() {
+ return completeState == SummaryActionState.COMPLETED;
+ }
+
@Override
public int compareTo(@NonNull SummaryAction o) {
if (o == null) {
diff --git a/library/main/src/com/android/car/setupwizardlib/summary/SummaryActionState.java b/library/main/src/com/android/car/setupwizardlib/summary/SummaryActionState.java
new file mode 100644
index 0000000..2b7daf2
--- /dev/null
+++ b/library/main/src/com/android/car/setupwizardlib/summary/SummaryActionState.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 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.car.setupwizardlib.summary;
+
+/** Complete state of the action. */
+public enum SummaryActionState {
+ COMPLETED,
+ NOT_COMPLETED,
+ WAITING_TO_RESOLVE
+}
diff --git a/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java b/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java
index c58e352..9528502 100644
--- a/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java
+++ b/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java
@@ -33,13 +33,12 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
-
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
/**
* Monitor that listens for changes in the driving state so that it can trigger an exit of the
- * setup wizard when {@link CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP}
+ * setup wizard when {@link CarUxRestrictions#UX_RESTRICTIONS_NO_SETUP}
* is active.
*/
public class CarDrivingStateMonitor implements
diff --git a/library/main/src/com/android/car/setupwizardlib/util/CarHelperRegistry.java b/library/main/src/com/android/car/setupwizardlib/util/CarHelperRegistry.java
index 01447aa..148ba32 100644
--- a/library/main/src/com/android/car/setupwizardlib/util/CarHelperRegistry.java
+++ b/library/main/src/com/android/car/setupwizardlib/util/CarHelperRegistry.java
@@ -17,11 +17,9 @@
package com.android.car.setupwizardlib.util;
import android.content.Context;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-
import java.util.concurrent.ConcurrentHashMap;
/** A registry of singleton-like helpers, which can be injected by the application for testing. */
diff --git a/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java b/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java
index 4e1d8ca..2740455 100644
--- a/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java
+++ b/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java
@@ -38,6 +38,9 @@ public final class CarSetupWizardUiUtils {
public static final String EXTRA_NEW_LANDSCAPE_LAYOUT_SUPPORTED =
"extra_new_landscape_layout_supported";
+ /* Setup Wizard Package Name **/
+ public static final String SETUP_WIZARD_PACKAGE = "com.google.android.car.setupwizard";
+
/** Hide system UI */
public static void hideSystemUI(Activity activity) {
maybeHideSystemUI(activity);
diff --git a/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java b/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java
index ff83b55..8f67220 100644
--- a/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java
+++ b/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java
@@ -20,153 +20,144 @@ import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
-/**
- * <p>Derived from {@code com.android.setupwizardlib/WizardManagerHelper.java}
- */
+/** Derived from {@code com.android.setupwizardlib/WizardManagerHelper.java} */
public final class CarWizardManagerHelper {
- public static final String EXTRA_WIZARD_BUNDLE = "wizardBundle";
- public static final String EXTRA_IS_FIRST_RUN = "firstRun";
- public static final String EXTRA_IS_DEALER = "dealer";
- public static final String EXTRA_IS_DEFERRED_SETUP = "deferredSetup";
- private static final String ACTION_NEXT = "com.android.wizard.NEXT";
- private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
-
- private CarWizardManagerHelper() {
- }
+ public static final String EXTRA_WIZARD_BUNDLE = "wizardBundle";
+ public static final String EXTRA_IS_FIRST_RUN = "firstRun";
+ public static final String EXTRA_IS_DEALER = "dealer";
+ public static final String EXTRA_IS_DEFERRED_SETUP = "deferredSetup";
+ private static final String ACTION_NEXT = "com.android.wizard.NEXT";
+ private static final String EXTRA_RESULT_CODE = "com.android.setupwizard.ResultCode";
- /**
- * 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);
- }
+ private CarWizardManagerHelper() {}
- /**
- * 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());
- }
+ /**
+ * 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);
+ }
- return intent;
+ /**
+ * 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());
}
- /**
- * 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));
- dstIntent.putExtra(EXTRA_IS_FIRST_RUN,
- srcIntent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false));
- dstIntent.putExtra(EXTRA_IS_DEALER,
- srcIntent.getBooleanExtra(EXTRA_IS_DEALER, false));
- dstIntent.putExtra(EXTRA_IS_DEFERRED_SETUP,
- srcIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false));
- }
+ return intent;
+ }
- /**
- * 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);
- }
+ /**
+ * 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));
+ dstIntent.putExtra(EXTRA_IS_FIRST_RUN, srcIntent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false));
+ dstIntent.putExtra(EXTRA_IS_DEALER, srcIntent.getBooleanExtra(EXTRA_IS_DEALER, false));
+ dstIntent.putExtra(
+ EXTRA_IS_DEFERRED_SETUP, srcIntent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false));
+ }
- /**
- * Checks whether an intent is running in the deferred 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 running in deferred setup wizard.
- */
- public static boolean isDeferredIntent(Intent intent) {
- return intent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, false);
- }
+ /**
+ * 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);
+ }
- /**
- * Check whether an intent is intended for the dealer.
- *
- * @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 isDealerIntent(Intent intent) {
- return intent.getBooleanExtra(EXTRA_IS_DEALER, false);
- }
+ /**
+ * Checks whether an intent is running in the deferred 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 running in deferred setup wizard.
+ */
+ public static boolean isDeferredIntent(Intent intent) {
+ return intent.getBooleanExtra(EXTRA_IS_DEFERRED_SETUP, 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(Context)
- */
- public static boolean isUserSetupComplete(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0) == 1;
- }
+ /**
+ * Check whether an intent is intended for the dealer.
+ *
+ * @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 isDealerIntent(Intent intent) {
+ return intent.getBooleanExtra(EXTRA_IS_DEALER, false);
+ }
- /**
- * 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(Context)
- */
- public static boolean isDeviceProvisioned(Context context) {
- return Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.DEVICE_PROVISIONED, 0) == 1;
- }
- /**
- * Checks whether an intent is running in the initial setup wizard flow.
- *
- * @param intent The intent to be checked, usually from {@link Activity#getIntent()}.
- * @return true if the intent passed in was intended to be used with setup wizard.
- */
- public static boolean isInitialSetupWizard(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(Context)
+ */
+ public static boolean isUserSetupComplete(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 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
- * 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 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(Context)
+ */
+ public static boolean isDeviceProvisioned(Context context) {
+ return Settings.Global.getInt(
+ context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)
+ == 1;
+ }
+ /**
+ * Checks whether an intent is running in the initial 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 isInitialSetupWizard(Intent intent) {
+ return intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false);
+ }
+
+ /**
+ * 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);
+ }
}
diff --git a/library/main/src/com/android/car/setupwizardlib/util/FeatureResolver.java b/library/main/src/com/android/car/setupwizardlib/util/FeatureResolver.java
new file mode 100644
index 0000000..8f0114f
--- /dev/null
+++ b/library/main/src/com/android/car/setupwizardlib/util/FeatureResolver.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2021 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.car.setupwizardlib.util;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class to resolve feature enablement and versions
+ */
+public class FeatureResolver {
+
+ private static final String TAG = FeatureResolver.class.getSimpleName();
+ private static volatile FeatureResolver sInstance = null;
+
+ static final String AUTHORITY =
+ CarSetupWizardUiUtils.SETUP_WIZARD_PACKAGE + ".feature_management";
+ static final String GET_FEATURE_VERSION_METHOD = "getFeatureVersion";
+ static final String SPLIT_NAV_LAYOUT_FEATURE = "split_nav_layout";
+ static final String G_MODAL_FEATURE = "g_modal";
+ static final String VALUE = "value";
+
+ private Context mContext;
+
+ private Map<String, Bundle> mResultMap = new HashMap<>();
+
+ /**
+ * Factory method to get an instance
+ */
+ public static FeatureResolver get(@NonNull Context context) {
+ if (sInstance == null) {
+ synchronized (FeatureResolver.class) {
+ if (sInstance == null) {
+ sInstance = new FeatureResolver(context);
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ /**
+ * Returns whether the alternative layout feature is enabled
+ */
+ public boolean isSplitNavLayoutFeatureEnabled() {
+ Bundle bundle;
+ if (mResultMap.containsKey(SPLIT_NAV_LAYOUT_FEATURE)) {
+ bundle = mResultMap.get(SPLIT_NAV_LAYOUT_FEATURE);
+ } else {
+ bundle = getFeatureBundle(SPLIT_NAV_LAYOUT_FEATURE);
+ mResultMap.put(SPLIT_NAV_LAYOUT_FEATURE, bundle);
+ }
+ boolean isSplitNavLayoutFeatureEnabled = bundle != null
+ && bundle.getBoolean(VALUE, false);
+ Log.v(TAG, String.format("isSplitNavLayoutEnabled: %s", isSplitNavLayoutFeatureEnabled));
+ return isSplitNavLayoutFeatureEnabled;
+ }
+
+ /**
+ * Returns the gModalVersion
+ */
+ public int getGModalVersion() {
+ Bundle bundle;
+ if (mResultMap.containsKey(G_MODAL_FEATURE)) {
+ bundle = mResultMap.get(G_MODAL_FEATURE);
+ } else {
+ bundle = getFeatureBundle(G_MODAL_FEATURE);
+ mResultMap.put(G_MODAL_FEATURE, bundle);
+ }
+
+ int gModalVersion = bundle != null ? bundle.getInt(VALUE, 0) : 0;
+ Log.v(TAG, String.format("gModalVersion: %s", gModalVersion));
+ return gModalVersion;
+ }
+
+ private Bundle getFeatureBundle(String feature) {
+ try {
+ Uri contentUri =
+ new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY)
+ .appendPath(GET_FEATURE_VERSION_METHOD)
+ .build();
+ return mContext.getContentResolver().call(
+ contentUri,
+ GET_FEATURE_VERSION_METHOD,
+ feature,
+ /* extras= */ null);
+ } catch (IllegalArgumentException exception) {
+ Log.w(TAG, String.format("Fail to resolve %s feature from suw provider", feature));
+ return null;
+ }
+ }
+
+ private FeatureResolver(Context context) {
+ this.mContext = context;
+ }
+}
diff --git a/library/main/tests/robotests/Android.bp b/library/main/tests/robotests/Android.bp
index d5cf533..9d91639 100644
--- a/library/main/tests/robotests/Android.bp
+++ b/library/main/tests/robotests/Android.bp
@@ -14,7 +14,7 @@ android_app {
privileged: true,
- libs: ["android.car"],
+ libs: ["android.car-system-stubs"],
static_libs: ["car-setup-wizard-lib"],
}
@@ -30,7 +30,7 @@ android_robolectric_test {
java_resource_dirs: ["config"],
libs: [
- "android.car",
+ "android.car-system-stubs",
],
instrumentation_for: "CarSetupWizardLib",
diff --git a/library/main/tests/robotests/res/layout/car_setup_wizard_layout_test_activity.xml b/library/main/tests/robotests/res/layout/car_setup_wizard_layout_test_activity.xml
index a9bcfbe..4509b0a 100644
--- a/library/main/tests/robotests/res/layout/car_setup_wizard_layout_test_activity.xml
+++ b/library/main/tests/robotests/res/layout/car_setup_wizard_layout_test_activity.xml
@@ -16,7 +16,9 @@
-->
<com.android.car.setupwizardlib.CarSetupWizardCompatLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/car_setup_wizard_layout"
android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ android:layout_height="match_parent"
+ app:supportsSplitNavLayout="true"/>
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/BaseCompatActivityTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/BaseCompatActivityTest.java
index 7209fc9..b504625 100644
--- a/library/main/tests/robotests/src/com/android/car/setupwizardlib/BaseCompatActivityTest.java
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/BaseCompatActivityTest.java
@@ -19,8 +19,10 @@ package com.android.car.setupwizardlib;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Activity;
import android.car.Car;
@@ -28,8 +30,11 @@ import android.car.CarNotConnectedException;
import android.car.drivingstate.CarUxRestrictions;
import android.car.drivingstate.CarUxRestrictionsManager;
import android.os.Bundle;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewStub;
import android.widget.Button;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.StyleRes;
@@ -38,7 +43,6 @@ import androidx.fragment.app.Fragment;
import com.android.car.setupwizardlib.robolectric.BaseRobolectricTest;
import com.android.car.setupwizardlib.robolectric.TestHelper;
import com.android.car.setupwizardlib.shadows.ShadowCar;
-import com.android.car.setupwizardlib.test.R;
import org.junit.Before;
import org.junit.Test;
@@ -194,6 +198,7 @@ public class BaseCompatActivityTest extends BaseRobolectricTest {
.isEqualTo(0);
// Verify that onContentFragmentSet is called with the test fragment
verify(spyBaseCompatActivity).onContentFragmentSet(fragment);
+ verify(spyBaseCompatActivity).getFragmentContainerViewId();
}
/**
@@ -213,6 +218,7 @@ public class BaseCompatActivityTest extends BaseRobolectricTest {
.isEqualTo(0);
// Verify that onContentFragmentSet is not called
verify(spyBaseCompatActivity, times(0)).onContentFragmentSet(fragment);
+ verify(spyBaseCompatActivity, times(0)).getFragmentContainerViewId();
}
/**
@@ -232,6 +238,7 @@ public class BaseCompatActivityTest extends BaseRobolectricTest {
.isEqualTo(1);
// Verify that onContentFragmentSet is called with the test fragment
verify(spyBaseCompatActivity).onContentFragmentSet(fragment);
+ verify(spyBaseCompatActivity).getFragmentContainerViewId();
}
/**
@@ -251,6 +258,7 @@ public class BaseCompatActivityTest extends BaseRobolectricTest {
.isEqualTo(0);
// Verify that onContentFragmentSet is not called
verify(spyBaseCompatActivity, times(0)).onContentFragmentSet(fragment);
+ verify(spyBaseCompatActivity, times(0)).getFragmentContainerViewId();
}
/**
@@ -294,12 +302,50 @@ public class BaseCompatActivityTest extends BaseRobolectricTest {
*/
@Test
public void testSetContentLayout() {
- mBaseCompatActivity.setContentLayout(R.layout.base_activity_test_layout);
- View contentLayout = mBaseCompatActivity.findViewById(R.id.content_layout);
+ BaseCompatActivity spyBaseCompatActivity = Mockito.spy(mBaseCompatActivity);
+
+ spyBaseCompatActivity.setContentLayout(R.layout.base_activity_test_layout);
+ View contentLayout = spyBaseCompatActivity.findViewById(R.id.content_layout);
+
assertThat(contentLayout).isNotNull();
}
/**
+ * Test that {@link BaseSetupWizardActivity#setContentLayout(int)} adds the specified layout
+ * to the main content when layout_content_stub is null.
+ */
+ @Test
+ public void testSetContentLayoutWhenViewStubIsNull() {
+ BaseCompatActivity spyBaseCompatActivity = Mockito.spy(mBaseCompatActivity);
+ LayoutInflater mockLayoutInflater = mock(LayoutInflater.class);
+ when(spyBaseCompatActivity.findViewById(R.id.layout_content_stub)).thenReturn(null);
+ when(spyBaseCompatActivity.getLayoutInflater()).thenReturn(mockLayoutInflater);
+
+ spyBaseCompatActivity.setContentLayout(R.layout.base_activity_test_layout);
+
+ verify(mockLayoutInflater, times(1))
+ .inflate(R.layout.base_activity_test_layout,
+ mBaseCompatActivity.getCarSetupWizardLayout());
+ }
+
+ /**
+ * Test that {@link BaseCompatActivity#setContentLayout(int)} adds the specified layout to
+ * the main content when layout_content_stub is not null.
+ */
+ @Test
+ public void testSetContentLayoutWhenViewStubNotNull() {
+ BaseCompatActivity spyBaseCompatActivity = Mockito.spy(mBaseCompatActivity);
+ ViewStub mockViewStub = mock(ViewStub.class);
+ when(spyBaseCompatActivity.findViewById(R.id.layout_content_stub)).thenReturn(mockViewStub);
+
+ spyBaseCompatActivity.setContentLayout(R.layout.base_activity_test_layout);
+
+ verify(mockViewStub, times(1))
+ .setLayoutResource(R.layout.base_activity_test_layout);
+ verify(mockViewStub, times(1)).inflate();
+ }
+
+ /**
* Test that {@link BaseCompatActivity#finishAction()} results in a call to
* {@link BaseCompatActivity#finish}.
*/
@@ -581,4 +627,61 @@ public class BaseCompatActivityTest extends BaseRobolectricTest {
spyBaseCompatActivity.nextAction(Activity.RESULT_OK);
verify(spyBaseCompatActivity, times(2)).startActivity(Mockito.any());
}
+
+ /**
+ * Test that {@link BaseCompatActivity#getFragmentContainerViewId()} returns
+ * layout_content_fragment when split-nav is enabled and view stub is not inflated yet.
+ */
+ @Test
+ public void testGetFragmentContainerViewId_viewStubNotInflated() {
+ BaseCompatActivity spyBaseCompatActivity = createSpyBaseCompatActivity();
+ FrameLayout mockFrameLayout = mock(FrameLayout.class);
+ ViewStub mockViewStub = mock(ViewStub.class);
+ when(spyBaseCompatActivity.findViewById(R.id.empty_fragment_frame_layout))
+ .thenReturn(mockFrameLayout);
+ when(spyBaseCompatActivity.findViewById(R.id.layout_content_stub)).thenReturn(mockViewStub);
+
+ int fragmentContainerViewId = spyBaseCompatActivity.getFragmentContainerViewId();
+
+ verify(mockViewStub, times(1)).inflate();
+ assertThat(fragmentContainerViewId).isEqualTo(R.id.empty_fragment_frame_layout);
+ }
+
+ /**
+ * Test that {@link BaseCompatActivity#getFragmentContainerViewId()} returns
+ * layout_content_fragment when split-nav is enabled and view stub is already inflated
+ * with frame layout for fragment attachment.
+ */
+ @Test
+ public void testGetFragmentContainerViewId_viewStubInflatedFrameLayout() {
+ BaseCompatActivity spyBaseCompatActivity = createSpyBaseCompatActivity();
+ FrameLayout mockFrameLayout = mock(FrameLayout.class);
+ when(spyBaseCompatActivity.findViewById(R.id.empty_fragment_frame_layout))
+ .thenReturn(mockFrameLayout);
+ when(spyBaseCompatActivity.findViewById(R.id.layout_content_stub))
+ .thenReturn(null);
+
+ int fragmentContainerViewId = spyBaseCompatActivity.getFragmentContainerViewId();
+
+ assertThat(fragmentContainerViewId).isEqualTo(R.id.empty_fragment_frame_layout);
+ }
+
+ /**
+ * Test that {@link BaseCompatActivity#getFragmentContainerViewId()} returns
+ * layout_content_fragment when split-nav is enabled and view stub is already inflated
+ * with some other view than fragment layout. The frame layout is not available for fragment
+ * attachment.
+ */
+ @Test
+ public void testGetFragmentContainerViewId_frameLayoutNotAvailable() {
+ BaseCompatActivity spyBaseCompatActivity = createSpyBaseCompatActivity();
+ when(spyBaseCompatActivity.findViewById(R.id.layout_content_stub))
+ .thenReturn(null);
+ when(spyBaseCompatActivity.findViewById(R.id.empty_fragment_frame_layout))
+ .thenReturn(null);
+
+ int fragmentContainerViewId = spyBaseCompatActivity.getFragmentContainerViewId();
+
+ assertThat(fragmentContainerViewId).isEqualTo(R.id.car_setup_wizard_layout);
+ }
}
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java
index 3ed02c0..9371947 100644
--- a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java
@@ -24,6 +24,7 @@ import android.app.Activity;
import android.content.res.ColorStateList;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
@@ -65,6 +66,7 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
private static final Locale LOCALE_IW_IL = new Locale("iw", "IL");
private CarSetupWizardCompatLayout mCarSetupWizardCompatLayout;
+ private CarSetupWizardLayoutInterface mCarSetupWizardLayoutInterface;
private static final String TEST_PACKAGE_NAME = "test.packageName";
@@ -85,9 +87,11 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
}
mCarSetupWizardCompatLayout = createCarSetupWizardCompatLayout();
- // Have to make this call first to ensure secondaryToolbar button is created from stub.
- mCarSetupWizardCompatLayout.setSecondaryToolbarButtonVisible(true);
- mCarSetupWizardCompatLayout.setSecondaryToolbarButtonVisible(false);
+ mCarSetupWizardLayoutInterface =
+ (CarSetupWizardLayoutInterface) mCarSetupWizardCompatLayout;
+ // Have to make this call first to ensure secondaryActionButton is created from stub.
+ mCarSetupWizardLayoutInterface.setSecondaryActionButtonVisible(true);
+ mCarSetupWizardLayoutInterface.setSecondaryActionButtonVisible(false);
}
/**
@@ -240,75 +244,108 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setPrimaryToolbarButtonVisible} does set the view
+ * Test that any call to setToolbarTitle calls toolbar's setText when split-nav is enabled.
+ */
+ @Test
+ public void testSetToolbarTitleWhenSplitNavEnabled() {
+ CarSetupWizardCompatLayout spyCarSetupWizardCompatLayout =
+ Mockito.spy(mCarSetupWizardCompatLayout);
+ TextView spyToolbar = Mockito.spy(mCarSetupWizardCompatLayout.getToolbarTitle());
+ spyCarSetupWizardCompatLayout.setToolbarTitle(null);
+
+ spyCarSetupWizardCompatLayout.setToolbarTitleText("test title");
+
+ Mockito.verify(spyToolbar, Mockito.never()).setText("test title");
+ }
+
+ /**
+ * Test that any call to setToolbarTitleStyle calls toolbar's setTextAppearance when split-nav
+ * is enabled.
+ */
+ @Test
+ public void testSetToolbarStyleWhenSplitNavEnabled() {
+ @StyleRes int newStyle = R.style.TextAppearance_Car_Body2;
+ CarSetupWizardCompatLayout spyCarSetupWizardCompatLayout =
+ Mockito.spy(mCarSetupWizardCompatLayout);
+ TextView spyToolbar = Mockito.spy(mCarSetupWizardCompatLayout.getToolbarTitle());
+ spyCarSetupWizardCompatLayout.setToolbarTitle(null);
+
+ spyCarSetupWizardCompatLayout.setToolbarTitleStyle(newStyle);
+
+ Mockito.verify(spyToolbar, Mockito.never()).setTextAppearance(newStyle);
+ }
+
+ /**
+ * Test that {@link CarSetupWizardCompatLayout#setPrimaryActionButtonVisible} does set the view
* visible/not visible.
*/
@Test
- public void testSetPrimaryToolbarButtonVisibleTrue() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getPrimaryToolbarButton();
+ public void testSetPrimaryActionButtonVisibleTrue() {
+ View primaryButton = mCarSetupWizardLayoutInterface.getPrimaryActionButton();
- mCarSetupWizardCompatLayout.setPrimaryToolbarButtonVisible(true);
- TestHelper.assertViewVisible(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setPrimaryActionButtonVisible(true);
+ TestHelper.assertViewVisible(primaryButton);
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setPrimaryToolbarButtonVisible} does set the view
+ * Test that {@link CarSetupWizardCompatLayout#setPrimaryActionButtonVisible} does set the view
* visible/not visible.
*/
@Test
- public void testSetPrimaryToolbarButtonVisibleFalse() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getPrimaryToolbarButton();
+ public void testSetPrimaryActionButtonVisibleFalse() {
+ View primaryButton = mCarSetupWizardLayoutInterface.getPrimaryActionButton();
- mCarSetupWizardCompatLayout.setPrimaryToolbarButtonVisible(false);
- TestHelper.assertViewNotVisible(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setPrimaryActionButtonVisible(false);
+ TestHelper.assertViewNotVisible(primaryButton);
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setPrimaryToolbarButtonEnabled} does set the view
+ * Test that {@link CarSetupWizardCompatLayout#setPrimaryActionButtonEnabled} does set the view
* enabled/not enabled.
*/
@Test
- public void testSetPrimaryToolbarButtonEnabledTrue() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getPrimaryToolbarButton();
+ public void testSetPrimaryActionButtonEnabledTrue() {
+ View primaryButton = mCarSetupWizardLayoutInterface.getPrimaryActionButton();
- mCarSetupWizardCompatLayout.setPrimaryToolbarButtonEnabled(true);
- TestHelper.assertViewEnabled(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setPrimaryActionButtonEnabled(true);
+ TestHelper.assertViewEnabled(primaryButton);
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setPrimaryToolbarButtonEnabled} does set the view
+ * Test that {@link CarSetupWizardCompatLayout#setPrimaryActionButtonEnabled} does set the view
* enabled/not enabled.
*/
@Test
- public void testSetPrimaryToolbarButtonEnabledFalse() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getPrimaryToolbarButton();
+ public void testSetPrimaryActionButtonEnabledFalse() {
+ View primaryButton = mCarSetupWizardLayoutInterface.getPrimaryActionButton();
- mCarSetupWizardCompatLayout.setPrimaryToolbarButtonEnabled(false);
- TestHelper.assertViewNotEnabled(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setPrimaryActionButtonEnabled(false);
+ TestHelper.assertViewNotEnabled(primaryButton);
}
/**
- * Tests that {@link CarSetupWizardCompatLayout#setPrimaryToolbarButtonText(String)} does set
- * the primary toolbar button text.
+ * Tests that {@link CarSetupWizardCompatLayout#setPrimaryActionButtonText(String)} does set
+ * the primary action button text.
*/
@Test
- public void testSetPrimaryToolbarButtonText() {
- mCarSetupWizardCompatLayout.setPrimaryToolbarButtonText("test title");
+ public void testSetPrimaryActionButtonText() {
+ mCarSetupWizardLayoutInterface.setPrimaryActionButtonText("test title");
TestHelper.assertTextEqual(
- mCarSetupWizardCompatLayout.getPrimaryToolbarButton(), "test title");
+ mCarSetupWizardLayoutInterface.getPrimaryActionButton(), "test title");
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setPrimaryToolbarButtonListener} does set the
- * primary toolbar button listener.
+ * Test that {@link CarSetupWizardCompatLayout#setPrimaryActionButtonListener} does set the
+ * primary action button listener.
*/
@Test
- public void testSetPrimaryToolbarButtonListener() {
+ public void testSetPrimaryActionButtonListener() {
View.OnClickListener spyListener = TestHelper.createSpyListener();
- mCarSetupWizardCompatLayout.setPrimaryToolbarButtonListener(spyListener);
- mCarSetupWizardCompatLayout.getPrimaryToolbarButton().performClick();
- Mockito.verify(spyListener).onClick(mCarSetupWizardCompatLayout.getPrimaryToolbarButton());
+ mCarSetupWizardLayoutInterface.setPrimaryActionButtonListener(spyListener);
+ mCarSetupWizardLayoutInterface.getPrimaryActionButton().performClick();
+ Mockito.verify(spyListener).onClick(
+ mCarSetupWizardLayoutInterface.getPrimaryActionButton());
}
/**
@@ -317,89 +354,89 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
*/
@Test
public void testCreatePrimaryButtonTrue() {
- Button currPrimaryToolbarButton = mCarSetupWizardCompatLayout.getPrimaryToolbarButton();
- Button primaryToolbarButton = mCarSetupWizardCompatLayout.createPrimaryToolbarButton(true);
+ Button currPrimaryActionButton = mCarSetupWizardLayoutInterface.getPrimaryActionButton();
+ Button primaryActionButton = mCarSetupWizardCompatLayout.createPrimaryToolbarButton(true);
- assertThat(primaryToolbarButton.getVisibility()).isEqualTo(
- currPrimaryToolbarButton.getVisibility());
- assertThat(primaryToolbarButton.isEnabled()).isEqualTo(
- currPrimaryToolbarButton.isEnabled());
- assertThat(primaryToolbarButton.getText()).isEqualTo(currPrimaryToolbarButton.getText());
- assertThat(primaryToolbarButton.getLayoutParams()).isEqualTo(
- currPrimaryToolbarButton.getLayoutParams());
+ assertThat(primaryActionButton.getVisibility()).isEqualTo(
+ currPrimaryActionButton.getVisibility());
+ assertThat(primaryActionButton.isEnabled()).isEqualTo(
+ currPrimaryActionButton.isEnabled());
+ assertThat(primaryActionButton.getText()).isEqualTo(currPrimaryActionButton.getText());
+ assertThat(primaryActionButton.getLayoutParams()).isEqualTo(
+ currPrimaryActionButton.getLayoutParams());
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setSecondaryToolbarButtonVisible} does set the
+ * Test that {@link CarSetupWizardCompatLayout#setSecondaryActionButtonVisible} does set the
* view visible/not visible.
*/
@Test
- public void testSetSecondaryToolbarButtonVisibleTrue() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getSecondaryToolbarButton();
+ public void testSetSecondaryActionButtonVisibleTrue() {
+ View secondaryButton = mCarSetupWizardLayoutInterface.getSecondaryActionButton();
- mCarSetupWizardCompatLayout.setSecondaryToolbarButtonVisible(true);
- TestHelper.assertViewVisible(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setSecondaryActionButtonVisible(true);
+ TestHelper.assertViewVisible(secondaryButton);
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setSecondaryToolbarButtonVisible} does set the
+ * Test that {@link CarSetupWizardCompatLayout#setSecondaryActionButtonVisible} does set the
* view visible/not visible.
*/
@Test
- public void testSetSecondaryToolbarButtonVisibleFalse() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getSecondaryToolbarButton();
+ public void testSetSecondaryActionButtonVisibleFalse() {
+ View secondaryButton = mCarSetupWizardLayoutInterface.getSecondaryActionButton();
- mCarSetupWizardCompatLayout.setSecondaryToolbarButtonVisible(false);
- TestHelper.assertViewNotVisible(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setSecondaryActionButtonVisible(false);
+ TestHelper.assertViewNotVisible(secondaryButton);
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setSecondaryToolbarButtonEnabled} does set the
+ * Test that {@link CarSetupWizardCompatLayout#setSecondaryActionButtonEnabled} does set the
* view enabled/not enabled.
*/
@Test
- public void testSetSecondaryToolbarButtonEnabledTrue() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getSecondaryToolbarButton();
+ public void testSetSecondaryActionButtonEnabledTrue() {
+ View secondaryButton = mCarSetupWizardLayoutInterface.getSecondaryActionButton();
- mCarSetupWizardCompatLayout.setSecondaryToolbarButtonEnabled(true);
- TestHelper.assertViewEnabled(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setSecondaryActionButtonEnabled(true);
+ TestHelper.assertViewEnabled(secondaryButton);
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setSecondaryToolbarButtonEnabled} does set the
+ * Test that {@link CarSetupWizardCompatLayout#setSecondaryActionButtonEnabled} does set the
* view enabled/not enabled.
*/
@Test
- public void testSetSecondaryToolbarButtonEnabledFalse() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getSecondaryToolbarButton();
+ public void testSetSecondaryActionButtonEnabledFalse() {
+ View secondaryButton = mCarSetupWizardLayoutInterface.getSecondaryActionButton();
- mCarSetupWizardCompatLayout.setSecondaryToolbarButtonEnabled(false);
- TestHelper.assertViewNotEnabled(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setSecondaryActionButtonEnabled(false);
+ TestHelper.assertViewNotEnabled(secondaryButton);
}
/**
- * Tests that {@link CarSetupWizardCompatLayout#setSecondaryToolbarButtonText(String)} does set
- * the secondary toolbar button text.
+ * Tests that {@link CarSetupWizardCompatLayout#setSecondaryActionButtonText(String)} does set
+ * the secondary action button text.
*/
@Test
- public void testSetSecondaryToolbarButtonText() {
- mCarSetupWizardCompatLayout.setSecondaryToolbarButtonText("test title");
+ public void testSetSecondaryActionButtonText() {
+ mCarSetupWizardLayoutInterface.setSecondaryActionButtonText("test title");
TestHelper.assertTextEqual(
- mCarSetupWizardCompatLayout.getSecondaryToolbarButton(), "test title");
+ mCarSetupWizardLayoutInterface.getSecondaryActionButton(), "test title");
}
/**
- * Test that {@link CarSetupWizardCompatLayout#setSecondaryToolbarButtonListener} does set the
- * secondary toolbar button listener.
+ * Test that {@link CarSetupWizardCompatLayout#setSecondaryActionButtonListener} does set the
+ * secondary action button listener.
*/
@Test
- public void testSetSecondaryToolbarButtonListener() {
+ public void testSetSecondaryActionButtonListener() {
View.OnClickListener spyListener = TestHelper.createSpyListener();
- mCarSetupWizardCompatLayout.setSecondaryToolbarButtonListener(spyListener);
- mCarSetupWizardCompatLayout.getSecondaryToolbarButton().performClick();
+ mCarSetupWizardLayoutInterface.setSecondaryActionButtonListener(spyListener);
+ mCarSetupWizardLayoutInterface.getSecondaryActionButton().performClick();
Mockito.verify(spyListener)
- .onClick(mCarSetupWizardCompatLayout.getSecondaryToolbarButton());
+ .onClick(mCarSetupWizardLayoutInterface.getSecondaryActionButton());
}
/**
@@ -408,10 +445,10 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
*/
@Test
public void testSetProgressBarVisibleTrue() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getProgressBar();
+ View progressBar = mCarSetupWizardCompatLayout.getProgressBar();
- mCarSetupWizardCompatLayout.setProgressBarVisible(true);
- TestHelper.assertViewVisible(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setProgressBarVisible(true);
+ TestHelper.assertViewVisible(progressBar);
}
/**
@@ -420,10 +457,10 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
*/
@Test
public void testSetProgressBarVisibleFalse() {
- View toolbarTitle = mCarSetupWizardCompatLayout.getProgressBar();
+ View progressBar = mCarSetupWizardCompatLayout.getProgressBar();
- mCarSetupWizardCompatLayout.setProgressBarVisible(false);
- TestHelper.assertViewNotVisible(toolbarTitle);
+ mCarSetupWizardLayoutInterface.setProgressBarVisible(false);
+ TestHelper.assertViewNotVisible(progressBar);
}
/**
@@ -432,7 +469,7 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
*/
@Test
public void testSetProgressBarIndeterminateTrue() {
- mCarSetupWizardCompatLayout.setProgressBarIndeterminate(true);
+ mCarSetupWizardLayoutInterface.setProgressBarIndeterminate(true);
assertThat(mCarSetupWizardCompatLayout.getProgressBar().isIndeterminate()).isTrue();
}
@@ -442,7 +479,7 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
*/
@Test
public void testSetProgressBarIndeterminateFalse() {
- mCarSetupWizardCompatLayout.setProgressBarIndeterminate(false);
+ mCarSetupWizardLayoutInterface.setProgressBarIndeterminate(false);
assertThat(mCarSetupWizardCompatLayout.getProgressBar().isIndeterminate()).isFalse();
}
@@ -451,7 +488,7 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
*/
@Test
public void testSetProgressBarProgress() {
- mCarSetupWizardCompatLayout.setProgressBarProgress(80);
+ mCarSetupWizardLayoutInterface.setProgressBarProgress(80);
assertThat(mCarSetupWizardCompatLayout.getProgressBar().getProgress()).isEqualTo(80);
}
@@ -459,22 +496,36 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
public void testApplyUpdatedLocale() {
mCarSetupWizardCompatLayout.applyLocale(LOCALE_IW_IL);
TextView toolbarTitle = mCarSetupWizardCompatLayout.getToolbarTitle();
- Button primaryToolbarButton = mCarSetupWizardCompatLayout.getPrimaryToolbarButton();
- Button secondaryToolbarButton = mCarSetupWizardCompatLayout.getSecondaryToolbarButton();
+ Button primaryActionButton = mCarSetupWizardLayoutInterface.getPrimaryActionButton();
+ Button secondaryActionButton = mCarSetupWizardLayoutInterface.getSecondaryActionButton();
assertThat(toolbarTitle.getTextLocale()).isEqualTo(LOCALE_IW_IL);
- assertThat(primaryToolbarButton.getTextLocale()).isEqualTo(LOCALE_IW_IL);
- assertThat(secondaryToolbarButton.getTextLocale()).isEqualTo(LOCALE_IW_IL);
+ assertThat(primaryActionButton.getTextLocale()).isEqualTo(LOCALE_IW_IL);
+ assertThat(secondaryActionButton.getTextLocale()).isEqualTo(LOCALE_IW_IL);
mCarSetupWizardCompatLayout.applyLocale(LOCALE_EN_US);
assertThat(toolbarTitle.getTextLocale()).isEqualTo(LOCALE_EN_US);
- assertThat(primaryToolbarButton.getTextLocale()).isEqualTo(LOCALE_EN_US);
- assertThat(secondaryToolbarButton.getTextLocale()).isEqualTo(LOCALE_EN_US);
+ assertThat(primaryActionButton.getTextLocale()).isEqualTo(LOCALE_EN_US);
+ assertThat(secondaryActionButton.getTextLocale()).isEqualTo(LOCALE_EN_US);
+ }
+
+ @Test
+ public void testApplyUpdatedLocaleWhenSplitNavEnabled() {
+ CarSetupWizardCompatLayout spyCarSetupWizardCompatLayout =
+ Mockito.spy(mCarSetupWizardCompatLayout);
+ TextView spyToolbar = Mockito.spy(mCarSetupWizardCompatLayout.getToolbarTitle());
+ spyCarSetupWizardCompatLayout.setToolbarTitle(null);
+
+ spyCarSetupWizardCompatLayout.applyLocale(LOCALE_EN_US);
+
+ Mockito.verify(spyToolbar, Mockito.never()).setTextLocale(LOCALE_EN_US);
+ Mockito.verify(spyToolbar, Mockito.never())
+ .setLayoutDirection(TextUtils.getLayoutDirectionFromLocale(LOCALE_EN_US));
}
@Test
public void testGetBackButton() {
- assertThat(mCarSetupWizardCompatLayout.getPrimaryToolbarButton()).isEqualTo(
+ assertThat(mCarSetupWizardLayoutInterface.getPrimaryActionButton()).isEqualTo(
mCarSetupWizardCompatLayout.findViewById(R.id.primary_toolbar_button));
}
@@ -485,14 +536,14 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
}
@Test
- public void testGetPrimaryToolBarButton() {
- assertThat(mCarSetupWizardCompatLayout.getPrimaryToolbarButton()).isEqualTo(
+ public void testGetPrimaryActionButton() {
+ assertThat(mCarSetupWizardLayoutInterface.getPrimaryActionButton()).isEqualTo(
mCarSetupWizardCompatLayout.findViewById(R.id.primary_toolbar_button));
}
@Test
- public void testGetSecondaryToolBarButton() {
- assertThat(mCarSetupWizardCompatLayout.getSecondaryToolbarButton()).isEqualTo(
+ public void testGetSecondaryActionButton() {
+ assertThat(mCarSetupWizardLayoutInterface.getSecondaryActionButton()).isEqualTo(
mCarSetupWizardCompatLayout.findViewById(R.id.secondary_toolbar_button));
}
@@ -509,10 +560,10 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
CarSetupWizardCompatLayout layout = createCarSetupWizardCompatLayout();
// Verify primary button background
- Button primary = layout.getPrimaryToolbarButton();
+ Button primary = layout.getPrimaryActionButton();
Drawable expected = application.getResources().getDrawable(R.drawable.button_ripple_bg);
- assertThat(getDrawbleDefaultColor(primary.getBackground()))
- .isEqualTo(getDrawbleDefaultColor(expected));
+ assertThat(getDrawableDefaultColor(primary.getBackground()))
+ .isEqualTo(getDrawableDefaultColor(expected));
// Verify primary button text size
assertThat(primary.getTextSize())
@@ -538,14 +589,15 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
CarSetupWizardCompatLayout layout = createCarSetupWizardCompatLayout();
ColorDrawable bg = (ColorDrawable) layout.getBackground();
- assertThat(bg).isNull();
+ assertThat(bg.getColor()).isEqualTo(
+ application.getResources().getColor(R.color.suw_color_background));
}
@Test
public void testSetButtonTextColor() {
setupFakeContentProvider();
CarSetupWizardCompatLayout layout = createCarSetupWizardCompatLayout();
- Button primary = layout.getPrimaryToolbarButton();
+ Button primary = layout.getPrimaryActionButton();
layout.setButtonTextColor(
primary, PartnerConfig.CONFIG_LAYOUT_BG_COLOR);
@@ -558,8 +610,8 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
public void testSetBackground() {
setupFakeContentProvider();
CarSetupWizardCompatLayout layout = createCarSetupWizardCompatLayout();
- layout.setSecondaryToolbarButtonVisible(true);
- Button secondary = layout.getSecondaryToolbarButton();
+ layout.setSecondaryActionButtonVisible(true);
+ Button secondary = layout.getSecondaryActionButton();
layout.setBackground(
secondary,
@@ -567,14 +619,14 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
PartnerConfig.CONFIG_TOOLBAR_SECONDARY_BUTTON_BG_COLOR);
Drawable expected = application.getResources().getDrawable(R.drawable.button_ripple_bg);
- assertThat(getDrawbleDefaultColor(secondary.getBackground()))
- .isEqualTo(getDrawbleDefaultColor(expected));
+ assertThat(getDrawableDefaultColor(secondary.getBackground()))
+ .isEqualTo(getDrawableDefaultColor(expected));
}
@Test
public void test_bothButtons_areStyled_inDefaultLayout() {
- Button primaryButton = mCarSetupWizardCompatLayout.getPrimaryToolbarButton();
- Button secondaryButton = mCarSetupWizardCompatLayout.getSecondaryToolbarButton();
+ Button primaryButton = mCarSetupWizardLayoutInterface.getPrimaryActionButton();
+ Button secondaryButton = mCarSetupWizardLayoutInterface.getSecondaryActionButton();
assertThat(primaryButton.getTextSize()).isWithin(TOLERANCE).of(EXCEPTED_TEXT_SIZE);
assertThat(secondaryButton.getTextSize()).isWithin(TOLERANCE).of(EXCEPTED_TEXT_SIZE);
@@ -588,8 +640,8 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
.get();
CarSetupWizardCompatLayout layout = activity.findViewById(R.id.car_setup_wizard_layout);
- Button primaryButton = layout.getPrimaryToolbarButton();
- Button secondaryButton = layout.getSecondaryToolbarButton();
+ Button primaryButton = layout.getPrimaryActionButton();
+ Button secondaryButton = layout.getSecondaryActionButton();
assertThat(primaryButton.getTextSize()).isWithin(TOLERANCE).of(EXCEPTED_TEXT_SIZE);
assertThat(secondaryButton.getTextSize()).isWithin(TOLERANCE).of(EXCEPTED_TEXT_SIZE);
@@ -615,7 +667,7 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
CarSetupWizardCompatLayout layout = activity.findViewById(R.id.car_setup_wizard_layout);
View toolbar = layout.findViewById(R.id.application_bar);
- assertThat(toolbar.getTextDirection()).isEqualTo(View.TEXT_DIRECTION_LTR);
+ assertThat(toolbar.getLayoutDirection()).isEqualTo(View.LAYOUT_DIRECTION_LTR);
assertThat(layout.shouldMirrorNavIcons()).isTrue();
}
@@ -632,7 +684,7 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
return activity.findViewById(R.id.car_setup_wizard_layout);
}
- private @ColorRes int getDrawbleDefaultColor(Drawable drawable) {
+ private @ColorRes int getDrawableDefaultColor(Drawable drawable) {
Drawable.ConstantState state = drawable.getConstantState();
ColorStateList colorStateList = ReflectionHelpers.getField(state, "mColor");
return colorStateList.getDefaultColor();
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/FakeFeatureManagementProvider.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/FakeFeatureManagementProvider.java
new file mode 100644
index 0000000..273f88e
--- /dev/null
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/FakeFeatureManagementProvider.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 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.car.setupwizardlib;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+import org.robolectric.Robolectric;
+
+/**
+ * An implementation of
+ * {@link com.google.android.car.setupwizard.common.config.FeatureManagementProvider} for
+ * Robolectric tests.
+ */
+public class FakeFeatureManagementProvider extends ContentProvider {
+ private static final String SUW_AUTHORITY =
+ "com.google.android.car.setupwizard.feature_management";
+ private static final String GET_FEATURE_VERSION_METHOD = "getFeatureVersion";
+ private static final String SPLIT_NAV_LAYOUT = "split_nav_layout";
+ private static final String TYPE = "type";
+ private static final String BOOLEAN_TYPE = "BOOLEAN";
+ private static final String VALUE = "value";
+
+ public static FakeFeatureManagementProvider installProvider() {
+ return Robolectric.setupContentProvider(FakeFeatureManagementProvider.class, SUW_AUTHORITY);
+ }
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor query(
+ Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ throw new UnsupportedOperationException("query operation not supported currently.");
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException("getType operation not supported currently.");
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException("insert operation not supported currently.");
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("delete operation not supported currently.");
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException("update operation not supported currently.");
+ }
+
+ @Override
+ public Bundle call(String method, String feature, Bundle extras) {
+ Bundle bundle = new Bundle();
+ if (!GET_FEATURE_VERSION_METHOD.equals(method)) {
+ return bundle;
+ }
+
+ switch(feature) {
+ case SPLIT_NAV_LAYOUT:
+ bundle.putString(TYPE, BOOLEAN_TYPE);
+ bundle.putBoolean(VALUE, true);
+ break;
+ default:
+ // Do nothing
+ }
+ return bundle;
+ }
+}
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/SplitNavLayoutTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/SplitNavLayoutTest.java
new file mode 100644
index 0000000..34f5a46
--- /dev/null
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/SplitNavLayoutTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2021 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.car.setupwizardlib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.car.setupwizardlib.partner.ExternalResources;
+import com.android.car.setupwizardlib.partner.FakeOverrideContentProvider;
+import com.android.car.setupwizardlib.partner.PartnerConfig;
+import com.android.car.setupwizardlib.partner.ResourceEntry;
+import com.android.car.setupwizardlib.robolectric.BaseRobolectricTest;
+import com.android.car.setupwizardlib.shadows.ShadowConfiguration;
+
+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 java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for split-nav layout
+ */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowConfiguration.class)
+public class SplitNavLayoutTest extends BaseRobolectricTest {
+ private static final String TEST_PACKAGE_NAME = "test.packageName";
+
+ private static final PartnerConfig ULTRA_WIDE_SCREEN_CONTENT_WIDTH_RESOURCE_NAME =
+ PartnerConfig.CONFIG_ULTRA_WIDE_SCREEN_CONTENT_WIDTH;
+
+ private static final int PARTNER_CONTENT_WIDTH = 1500;
+
+ private FakeOverrideContentProvider mFakeOverrideContentProvider;
+
+ @Before
+ public void setUp() {
+ mFakeOverrideContentProvider = FakeOverrideContentProvider.installEmptyProvider();
+ FakeFeatureManagementProvider.installProvider();
+ }
+
+ @Test
+ @Config(qualifiers = "w1760dp-land")
+ public void test_UltraWideContentWidth_isSetToCustomWidth() {
+ List<ResourceEntry> resourceEntries = prepareCustomContentWidth();
+ for (ResourceEntry entry : resourceEntries) {
+ mFakeOverrideContentProvider.injectResourceEntry(entry);
+ }
+
+ Activity activity = Robolectric.buildActivity(CarSetupWizardLayoutTestActivity.class)
+ .create()
+ .get();
+ View contentContainer = activity.findViewById(R.id.ultra_wide_content_container);
+ ViewGroup.LayoutParams layoutParams = contentContainer.getLayoutParams();
+ assertThat(layoutParams.width).isEqualTo(PARTNER_CONTENT_WIDTH);
+ }
+
+ @Test
+ @Config(qualifiers = "w1760dp-land")
+ public void test_UltraWideContentWidthIsSetTo0_withoutCustomValue() {
+ Activity activity = Robolectric.buildActivity(CarSetupWizardLayoutTestActivity.class)
+ .create()
+ .get();
+
+ View contentContainer = activity.findViewById(R.id.ultra_wide_content_container);
+ ViewGroup.LayoutParams layoutParams = contentContainer.getLayoutParams();
+ assertThat(layoutParams.width).isEqualTo(0);
+ }
+
+ @Test
+ @Config(qualifiers = "iw-w1250dp-land")
+ public void test_layoutDirectionIsLtr_inRtrLocale() {
+ Activity activity = Robolectric.buildActivity(CarSetupWizardLayoutTestActivity.class)
+ .create()
+ .get();
+
+ View layout = activity.findViewById(R.id.car_setup_wizard_layout);
+ assertThat(layout.getLayoutDirection()).isEqualTo(View.LAYOUT_DIRECTION_LTR);
+
+ View buttonContainer = activity.findViewById(R.id.button_container);
+ assertThat(buttonContainer.getLayoutDirection()).isEqualTo(View.LAYOUT_DIRECTION_LTR);
+ }
+
+ @Test
+ @Config(qualifiers = "iw-w1760dp-land")
+ public void test_layoutDirectionIsLtrInUltraWide_isRtrLocale() {
+ Activity activity = Robolectric.buildActivity(CarSetupWizardLayoutTestActivity.class)
+ .create()
+ .get();
+
+ View layout = activity.findViewById(R.id.car_setup_wizard_layout);
+ assertThat(layout.getLayoutDirection()).isEqualTo(View.LAYOUT_DIRECTION_LTR);
+
+ View buttonContainer = activity.findViewById(R.id.button_container);
+ assertThat(buttonContainer.getLayoutDirection()).isEqualTo(View.LAYOUT_DIRECTION_LTR);
+ }
+
+ private List<ResourceEntry> prepareCustomContentWidth() {
+ ExternalResources.Resources testResources =
+ ExternalResources.injectExternalResources(TEST_PACKAGE_NAME);
+
+ testResources.putDimension(
+ ULTRA_WIDE_SCREEN_CONTENT_WIDTH_RESOURCE_NAME.getResourceName(),
+ PARTNER_CONTENT_WIDTH);
+
+ return Arrays.asList(
+ new ResourceEntry(
+ TEST_PACKAGE_NAME,
+ ULTRA_WIDE_SCREEN_CONTENT_WIDTH_RESOURCE_NAME.getResourceName(),
+ testResources.getIdentifier(
+ ULTRA_WIDE_SCREEN_CONTENT_WIDTH_RESOURCE_NAME.getResourceName(),
+ /* defType= */ "dimen",
+ TEST_PACKAGE_NAME))
+ );
+ }
+}
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/FeatureResolverTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/FeatureResolverTest.java
new file mode 100644
index 0000000..6951030
--- /dev/null
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/FeatureResolverTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 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.car.setupwizardlib.util;
+
+import static com.android.car.setupwizardlib.util.FeatureResolver.VALUE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.car.setupwizardlib.robolectric.BaseRobolectricTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.robolectric.RobolectricTestRunner;
+
+import java.lang.reflect.Constructor;
+
+@RunWith(RobolectricTestRunner.class)
+public class FeatureResolverTest extends BaseRobolectricTest {
+
+ @Mock
+ private ContentResolver mContentResolver;
+
+ private FeatureResolver mFeatureResolver;
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ Constructor<FeatureResolver> constructor = FeatureResolver.class
+ .getDeclaredConstructor(Context.class);
+ constructor.setAccessible(true);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mFeatureResolver = constructor.newInstance(mContext);
+ doReturn(mContentResolver).when(mContext).getContentResolver();
+ }
+
+ @Test
+ public void testFeatureResolverInstance() {
+ assertThat(FeatureResolver.get(mContext)).isNotNull();
+ }
+
+ @Test
+ public void testFeatureResolverSingletonInstance() {
+ FeatureResolver instance = FeatureResolver.get(mContext);
+
+ assertThat(instance).isEqualTo(FeatureResolver.get(mContext));
+ }
+
+ @Test
+ public void testIsSplitNavLayoutFeatureEnabled_whenReturnsTrue() {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(VALUE, true);
+ doReturn(bundle).when(mContentResolver).call((Uri) any(), any(), any(), any());
+
+ boolean isSplitNavLayoutFeatureEnabled = mFeatureResolver.isSplitNavLayoutFeatureEnabled();
+
+ assertThat(isSplitNavLayoutFeatureEnabled).isTrue();
+ }
+
+ @Test
+ public void testIsSplitNavLayoutFeatureEnabled_whenReturnsFalse() {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(VALUE, false);
+ doReturn(bundle).when(mContentResolver).call((Uri) any(), any(), any(), any());
+
+ boolean isSplitNavLayoutFeatureEnabled = mFeatureResolver.isSplitNavLayoutFeatureEnabled();
+
+ assertThat(isSplitNavLayoutFeatureEnabled).isFalse();
+ }
+
+ @Test
+ public void testIsSplitNavLayoutFeatureEnabled_whenReturnsBundleNull() {
+ doReturn(null).when(mContentResolver).call((Uri) any(), any(), any(), any());
+
+ boolean isSplitNavLayoutFeatureEnabled = mFeatureResolver.isSplitNavLayoutFeatureEnabled();
+
+ assertThat(isSplitNavLayoutFeatureEnabled).isFalse();
+ }
+
+ @Test
+ public void testGetGModalVersion_whenVersionNumber1() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(VALUE, 1);
+ doReturn(bundle).when(mContentResolver).call((Uri) any(), any(), any(), any());
+
+ int splitNavLayoutFeatureVersion = mFeatureResolver.getGModalVersion();
+
+ assertThat(splitNavLayoutFeatureVersion).isEqualTo(1);
+ }
+
+ @Test
+ public void testGModalVersion_whenVersionNumber0() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(VALUE, 0);
+ doReturn(bundle).when(mContentResolver).call((Uri) any(), any(), any(), any());
+
+ int splitNavLayoutFeatureVersion = mFeatureResolver.getGModalVersion();
+
+ assertThat(splitNavLayoutFeatureVersion).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetGModalVersion_whenReturnsBundleNull() {
+ doReturn(null).when(mContentResolver).call((Uri) any(), any(), any(), any());
+
+ int splitNavLayoutFeatureVersion = mFeatureResolver.getGModalVersion();
+
+ assertThat(splitNavLayoutFeatureVersion).isEqualTo(0);
+ }
+}
diff --git a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java
index 6c7830f..171710c 100644
--- a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java
+++ b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java
@@ -316,7 +316,7 @@ public class InitialLockSetupClient implements ServiceConnection {
new LockConfig(
/* enabled= */ true,
km.getMinLockLength(
- /* isPin= */ true, PasswordComplexity.PASSWORD_COMPLEXITY_LOW));
+ /* isPin= */ true, PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM));
patternConfig =
new LockConfig(
/* enabled= */ true,
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..d8c51f0
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+include ':car-setup-wizard-lib'
+project(':car-setup-wizard-lib').projectDir = new File('./library/main')
+
+rootProject.name='CarSetupWizard'