summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-06-23 02:35:51 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-06-23 02:35:51 +0000
commit512a203bac1165b77bb4625401b15dc712cd50e6 (patch)
tree033a2ea54f61c1238a5e634fdcc6ee9b4c81fc3a
parentd2c5b7d21ae8fada5dfc60cab11d29f66b2fee0c (diff)
parentfc6ed7a379bf120a3016a38976a7ea192763e3bf (diff)
downloadsetupwizard-android12-mainline-neuralnetworks-release.tar.gz
Change-Id: Ida4363cf531e4277bec0795461ae803d25052c9e
-rw-r--r--library/main/Android.bp6
-rw-r--r--library/main/AndroidManifest-gradle.xml20
-rw-r--r--library/main/build.gradle85
-rw-r--r--library/main/res/drawable/car_ic_close.xml25
-rw-r--r--library/main/res/layout/car_setup_wizard_toolbar.xml9
-rw-r--r--library/main/res/values-w1240dp-land/config.xml (renamed from library/main/res/values-w1280dp/config.xml)0
-rw-r--r--library/main/res/values-w1240dp-land/dimens.xml22
-rw-r--r--library/main/res/values-w1280dp-port/dimens.xml20
-rw-r--r--library/main/res/values-w1920dp-land/dimens.xml22
-rw-r--r--library/main/res/values/attrs.xml75
-rw-r--r--library/main/res/values/colors.xml13
-rw-r--r--library/main/res/values/dimens.xml30
-rw-r--r--library/main/res/values/integers.xml26
-rw-r--r--library/main/res/values/strings.xml3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/BaseActivity.java2
-rw-r--r--library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java20
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java100
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java3
-rw-r--r--library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java2
-rw-r--r--library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java6
-rw-r--r--library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java7
-rw-r--r--library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java9
-rw-r--r--library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java2
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java119
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java6
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java21
-rw-r--r--library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java4
-rw-r--r--library/main/tests/robotests/Android.bp4
-rw-r--r--library/main/tests/robotests/AndroidManifest.xml2
-rw-r--r--library/main/tests/robotests/res/values/attrs.xml2
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/BaseCompatActivityTest.java1
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java95
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutAlternativeActivity.java2
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutTestActivity.java2
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/shadows/ShadowConfiguration.java51
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitorTest.java22
-rw-r--r--library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtilsTest.java6
-rw-r--r--library/utils/Android.bp4
-rw-r--r--library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java194
-rw-r--r--library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java18
-rw-r--r--library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java9
42 files changed, 944 insertions, 128 deletions
diff --git a/library/main/Android.bp b/library/main/Android.bp
index b7cc78f..f99ecdd 100644
--- a/library/main/Android.bp
+++ b/library/main/Android.bp
@@ -13,6 +13,10 @@
// limitations under the License.
//
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
android_library {
name: "car-setup-wizard-lib",
srcs: ["src/**/*.java"],
@@ -22,5 +26,5 @@ android_library {
optimize: {
enabled: false,
},
- min_sdk_version: "26",
+ min_sdk_version: "28",
}
diff --git a/library/main/AndroidManifest-gradle.xml b/library/main/AndroidManifest-gradle.xml
new file mode 100644
index 0000000..cc9c1ab
--- /dev/null
+++ b/library/main/AndroidManifest-gradle.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.car.setupwizardlib">
+</manifest>
diff --git a/library/main/build.gradle b/library/main/build.gradle
new file mode 100644
index 0000000..412e3b0
--- /dev/null
+++ b/library/main/build.gradle
@@ -0,0 +1,85 @@
+// 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.
+//
+
+// Library-level build file
+
+apply plugin: 'com.android.library'
+
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+}
+
+android {
+ compileSdkVersion 30
+
+ defaultConfig {
+ minSdkVersion 28
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest-gradle.xml'
+ res.srcDirs = ['res']
+ java.srcDirs = ['src']
+ }
+
+ test {
+ manifest.srcFile 'tests/robotests/AndroidManifest.xml'
+ res.srcDirs += ['tests/robotests/res','tests/robotests/config']
+ java.srcDirs = ['tests/robotests/src']
+ }
+ }
+
+ android {
+ lintOptions {
+ abortOnError false
+ }
+ }
+
+ testOptions {
+ unitTests {
+ includeAndroidResources = true
+ }
+ }
+}
+
+dependencies {
+ implementation files('../../../../../../prebuilts/sdk/30/system/android.car-system-stubs.jar')
+
+ implementation 'androidx.car:car:1.0.0-alpha7'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.cardview:cardview:1.0.0'
+ implementation 'androidx.recyclerview:recyclerview:1.2.0'
+ implementation 'androidx.gridlayout:gridlayout:1.0.0'
+ implementation 'androidx.preference:preference:1.1.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation 'androidx.core:core:1.3.2'
+ implementation 'androidx.annotation:annotation:1.2.0'
+
+ testImplementation 'com.google.truth:truth:0.41'
+ testImplementation 'org.mockito:mockito-core:3.6.0'
+ testImplementation 'org.robolectric:robolectric:4.5.1'
+}
diff --git a/library/main/res/drawable/car_ic_close.xml b/library/main/res/drawable/car_ic_close.xml
new file mode 100644
index 0000000..08b5e36
--- /dev/null
+++ b/library/main/res/drawable/car_ic_close.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/car_primary_icon_size"
+ android:height="@dimen/car_primary_icon_size"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12 19,6.41z"
+ android:fillColor="@color/car_tint_light"/>
+</vector>
diff --git a/library/main/res/layout/car_setup_wizard_toolbar.xml b/library/main/res/layout/car_setup_wizard_toolbar.xml
index 5c5703b..5ae4e11 100644
--- a/library/main/res/layout/car_setup_wizard_toolbar.xml
+++ b/library/main/res/layout/car_setup_wizard_toolbar.xml
@@ -37,6 +37,15 @@
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"
+ android:background="@drawable/button_ripple_bg"
+ android:contentDescription="@string/close_button_content_description"
+ android:src="@drawable/car_ic_close"/>
</FrameLayout>
<TextView
diff --git a/library/main/res/values-w1280dp/config.xml b/library/main/res/values-w1240dp-land/config.xml
index 98343f3..98343f3 100644
--- a/library/main/res/values-w1280dp/config.xml
+++ b/library/main/res/values-w1240dp-land/config.xml
diff --git a/library/main/res/values-w1240dp-land/dimens.xml b/library/main/res/values-w1240dp-land/dimens.xml
new file mode 100644
index 0000000..257d03a
--- /dev/null
+++ b/library/main/res/values-w1240dp-land/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <dimen name="suw_page_margin_horizontal">64dp</dimen>
+ <!-- The column inner padding of a two-column layout -->
+ <dimen name="suw_column_inner_padding_horizontal">48dp</dimen>
+</resources> \ No newline at end of file
diff --git a/library/main/res/values-w1280dp-port/dimens.xml b/library/main/res/values-w1280dp-port/dimens.xml
new file mode 100644
index 0000000..1a3d98e
--- /dev/null
+++ b/library/main/res/values-w1280dp-port/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <dimen name="suw_page_margin_horizontal">148dp</dimen>
+</resources> \ No newline at end of file
diff --git a/library/main/res/values-w1920dp-land/dimens.xml b/library/main/res/values-w1920dp-land/dimens.xml
new file mode 100644
index 0000000..6e5add0
--- /dev/null
+++ b/library/main/res/values-w1920dp-land/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <dimen name="suw_page_margin_horizontal">132dp</dimen>
+ <!-- The column inner padding of a two-column layout -->
+ <dimen name="suw_column_inner_padding_horizontal">80dp</dimen>
+</resources> \ No newline at end of file
diff --git a/library/main/res/values/attrs.xml b/library/main/res/values/attrs.xml
index 957f3dd..31d2f5b 100644
--- a/library/main/res/values/attrs.xml
+++ b/library/main/res/values/attrs.xml
@@ -15,56 +15,81 @@
limitations under the License.
-->
<resources>
+ <!-- Attributes related to the visibility of the back button -->
+ <attr name="showBackButton" format="boolean"/>
+
+ <!-- Attributes related to the visibility and text of the toolbar title -->
+ <attr name="showToolbarTitle" format="boolean"/>
+ <attr name="toolbarTitleText" format="string"/>
+
+ <!-- Attributes related to the visibility and text of primary continue button -->
+ <attr name="showPrimaryToolbarButton" format="boolean"/>
+ <attr name="primaryToolbarButtonText" format="string"/>
+ <attr name="primaryToolbarButtonEnabled" format="boolean"/>
+ <attr name="primaryToolbarButtonFlat" format="boolean"/>
+
+ <!-- Attributes related to the visibility and text of secondary continue button -->
+ <attr name="showSecondaryToolbarButton" format="boolean"/>
+ <attr name="secondaryToolbarButtonText" format="string"/>
+ <attr name="secondaryToolbarButtonEnabled" format="boolean"/>
+
+ <!-- Attributes related to the visibility and indeterminate/determinate state
+ of the progress bar -->
+ <attr name="showProgressBar"/>
+ <attr name="indeterminateProgressBar"/>
+
<!-- Custom attribute definitions for the CarSetupWizardLayout -->
<declare-styleable name="CarSetupWizardLayout">
<!-- Attributes related to the visibility of the back button -->
- <attr name="showBackButton" format="boolean"/>
+ <attr name="showBackButton"/>
<!-- Attributes related to the visibility and text of the toolbar title -->
- <attr name="showToolbarTitle" format="boolean"/>
- <attr name="toolbarTitleText" format="string"/>
+ <attr name="showToolbarTitle"/>
+ <attr name="toolbarTitleText"/>
<!-- Attributes related to the visibility and text of primary continue button -->
- <attr name="showPrimaryToolbarButton" format="boolean"/>
- <attr name="primaryToolbarButtonText" format="string"/>
- <attr name="primaryToolbarButtonEnabled" format="boolean"/>
- <attr name="primaryToolbarButtonFlat" format="boolean"/>
+ <attr name="showPrimaryToolbarButton"/>
+ <attr name="primaryToolbarButtonText"/>
+ <attr name="primaryToolbarButtonEnabled"/>
+ <attr name="primaryToolbarButtonFlat"/>
<!-- Attributes related to the visibility and text of secondary continue button -->
- <attr name="showSecondaryToolbarButton" format="boolean"/>
- <attr name="secondaryToolbarButtonText" format="string"/>
- <attr name="secondaryToolbarButtonEnabled" format="boolean"/>
+ <attr name="showSecondaryToolbarButton"/>
+ <attr name="secondaryToolbarButtonText"/>
+ <attr name="secondaryToolbarButtonEnabled"/>
<!-- Attributes related to the visibility and indeterminate/determinate state
of the progress bar -->
- <attr name="showProgressBar" format="boolean"/>
- <attr name="indeterminateProgressBar" format="boolean"/>
+ <attr name="showProgressBar"/>
+ <attr name="indeterminateProgressBar" />
</declare-styleable>
<!-- Custom attribute definitions for the CarSetupWizardBaseLayout -->
<declare-styleable name="CarSetupWizardBaseLayout">
<!-- Attributes related to the visibility of the back button -->
- <attr name="showBackButton" format="boolean"/>
+ <attr name="showBackButton"/>
+ <!-- Attributes related to the visibility of the close button -->
+ <attr name="showCloseButton" format="boolean"/>
<!-- Attributes related to the visibility and text of the toolbar title -->
- <attr name="showToolbarTitle" format="boolean"/>
- <attr name="toolbarTitleText" format="string"/>
+ <attr name="showToolbarTitle"/>
+ <attr name="toolbarTitleText"/>
<!-- Attributes related to the visibility and text of primary continue button -->
- <attr name="showPrimaryToolbarButton" format="boolean"/>
- <attr name="primaryToolbarButtonText" format="string"/>
- <attr name="primaryToolbarButtonEnabled" format="boolean"/>
- <attr name="primaryToolbarButtonFlat" format="boolean"/>
+ <attr name="showPrimaryToolbarButton"/>
+ <attr name="primaryToolbarButtonText"/>
+ <attr name="primaryToolbarButtonEnabled"/>
+ <attr name="primaryToolbarButtonFlat"/>
<!-- Attributes related to the visibility and text of secondary continue button -->
- <attr name="showSecondaryToolbarButton" format="boolean"/>
- <attr name="secondaryToolbarButtonText" format="string"/>
- <attr name="secondaryToolbarButtonEnabled" format="boolean"/>
+ <attr name="showSecondaryToolbarButton"/>
+ <attr name="secondaryToolbarButtonText" />
+ <attr name="secondaryToolbarButtonEnabled"/>
<!-- Attributes related to the visibility and indeterminate/determinate state
of the progress bar -->
- <attr name="showProgressBar" format="boolean"/>
- <attr name="indeterminateProgressBar" format="boolean"/>
+ <attr name="showProgressBar"/>
+ <attr name="indeterminateProgressBar"/>
</declare-styleable>
-</resources> \ No newline at end of file
+</resources>
diff --git a/library/main/res/values/colors.xml b/library/main/res/values/colors.xml
index 6767e03..a3df84d 100644
--- a/library/main/res/values/colors.xml
+++ b/library/main/res/values/colors.xml
@@ -23,4 +23,17 @@
<color name="blue_400">#6BA5ED</color>
<color name="car_suw_tint">@color/blue_400</color>
+
+ <!-- White -->
+ <color name="suw_color_primary">@android:color/white</color>
+ <!-- Material grey500 -->
+ <color name="suw_color_secondary">#9AA0A6</color>
+ <!-- Material blue300 -->
+ <color name="suw_color_accent">#8AB4F8</color>
+ <!-- Material grey200 -->
+ <color name="suw_color_list_icon">#E8EAED</color>
+ <!-- Material grey800 -->
+ <color name="suw_color_divider">#3C4043</color>
+ <!-- Material grey900 -->
+ <color name="suw_color_background">#202124</color>
</resources>
diff --git a/library/main/res/values/dimens.xml b/library/main/res/values/dimens.xml
new file mode 100644
index 0000000..db6c833
--- /dev/null
+++ b/library/main/res/values/dimens.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <dimen name="suw_padding_3">16dp</dimen>
+ <dimen name="suw_padding_4">24dp</dimen>
+ <dimen name="suw_padding_5">32dp</dimen>
+ <dimen name="suw_padding_6">48dp</dimen>
+ <dimen name="suw_padding_7">64dp</dimen>
+ <dimen name="suw_padding_8">96dp</dimen>
+ <dimen name="suw_padding_9">128dp</dimen>
+
+ <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>
+</resources> \ No newline at end of file
diff --git a/library/main/res/values/integers.xml b/library/main/res/values/integers.xml
new file mode 100644
index 0000000..f7c13cd
--- /dev/null
+++ b/library/main/res/values/integers.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <!-- The layout_weight of two-column layout -->
+ <integer name="suw_title_column_weight">5</integer>
+ <integer name="suw_content_column_weight">7</integer>
+
+ <!-- The layout_weight of single-column layout -->
+ <integer name="suw_page_content_weight">3</integer>
+ <integer name="suw_page_filler_weight">1</integer>
+</resources> \ No newline at end of file
diff --git a/library/main/res/values/strings.xml b/library/main/res/values/strings.xml
index beb37dc..027a683 100644
--- a/library/main/res/values/strings.xml
+++ b/library/main/res/values/strings.xml
@@ -17,4 +17,7 @@
<resources>
<!-- Content description of the back button for accessibility services like Tallback [CHAR LIMIT=120] -->
<string name="back_button_content_description">Navigate back</string>
+
+ <!-- Content description of the close button for accessibility services like Tallback [CHAR LIMIT=120] -->
+ <string name="close_button_content_description">Close</string>
</resources> \ No newline at end of file
diff --git a/library/main/src/com/android/car/setupwizardlib/BaseActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseActivity.java
index 4fe59e7..edd2b73 100644
--- a/library/main/src/com/android/car/setupwizardlib/BaseActivity.java
+++ b/library/main/src/com/android/car/setupwizardlib/BaseActivity.java
@@ -16,12 +16,12 @@
package com.android.car.setupwizardlib;
-import android.annotation.CallSuper;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
+import androidx.annotation.CallSuper;
import androidx.annotation.LayoutRes;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
diff --git a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
index 3da7df6..36caae0 100644
--- a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
+++ b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
@@ -16,12 +16,12 @@
package com.android.car.setupwizardlib;
-import android.annotation.CallSuper;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
+import androidx.annotation.CallSuper;
import androidx.annotation.LayoutRes;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
@@ -97,6 +97,8 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
}
});
+ mCarSetupWizardLayout.setCloseButtonListener(v-> handleCloseButton());
+
resetPrimaryToolbarButtonOnClickListener();
resetSecondaryToolbarButtonOnClickListener();
@@ -255,6 +257,14 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
}
/**
+ * Method to be overwritten by subclasses wanting to implement their own close behavior.
+ * Default behavior is finishAction.
+ */
+ protected void handleCloseButton() {
+ finishAction();
+ }
+
+ /**
* Called when nextAction has been invoked, should be overridden on derived class when it is
* needed perform work when nextAction has been invoked.
*/
@@ -350,6 +360,14 @@ abstract class BaseSetupWizardActivity extends FragmentActivity {
}
/**
+ * Sets whether the close button is visible. If this value is {@code true}, clicking the button
+ * will finish the current flow.
+ */
+ protected void setCloseButtonVisible(boolean visible) {
+ mCarSetupWizardLayout.setCloseButtonVisible(visible);
+ }
+
+ /**
* Sets whether the toolbar title is visible.
*/
protected void setToolbarTitleVisible(boolean visible) {
diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java
index 7a7808d..715315a 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java
@@ -16,7 +16,6 @@
package com.android.car.setupwizardlib;
-import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
@@ -41,6 +40,7 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
+import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
@@ -59,8 +59,11 @@ import java.util.Objects;
class CarSetupWizardBaseLayout extends LinearLayout {
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 View mBackButton;
+ private View mCloseButton;
private View mTitleBar;
private TextView mToolbarTitle;
private PartnerConfigHelper mPartnerConfigHelper;
@@ -118,6 +121,7 @@ class CarSetupWizardBaseLayout extends LinearLayout {
*/
private void init(TypedArray attrArray) {
boolean showBackButton;
+ boolean showCloseButton;
boolean showToolbarTitle;
String toolbarTitleText;
@@ -136,6 +140,8 @@ class CarSetupWizardBaseLayout extends LinearLayout {
try {
showBackButton = attrArray.getBoolean(
R.styleable.CarSetupWizardBaseLayout_showBackButton, true);
+ showCloseButton = attrArray.getBoolean(
+ R.styleable.CarSetupWizardBaseLayout_showCloseButton, false);
showToolbarTitle = attrArray.getBoolean(
R.styleable.CarSetupWizardBaseLayout_showToolbarTitle, false);
toolbarTitleText = attrArray.getString(
@@ -164,15 +170,39 @@ class CarSetupWizardBaseLayout extends LinearLayout {
LayoutInflater inflater = LayoutInflater.from(getContext());
inflater.inflate(R.layout.car_setup_wizard_layout, this);
+ View toolbar = findViewById(R.id.application_bar);
+ // The toolbar will not be mirrored in RTL
+ toolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
- // Set the back button visibility based on the custom attribute.
setBackButton(findViewById(R.id.back_button));
+ setCloseButton(findViewById(R.id.close_button));
+
Drawable drawable = mPartnerConfigHelper.getDrawable(
getContext(), PartnerConfig.CONFIG_TOOLBAR_BUTTON_ICON_BACK);
if (drawable != null) {
((ImageView) mBackButton).setImageDrawable(drawable);
}
+
+ Drawable closeButtonDrawable = mPartnerConfigHelper.getDrawable(
+ getContext(), PartnerConfig.CONFIG_TOOLBAR_BUTTON_ICON_CLOSE);
+ if (closeButtonDrawable != null) {
+ ((ImageView) mCloseButton).setImageDrawable(closeButtonDrawable);
+ }
+
+ if (shouldMirrorNavIcons()) {
+ Log.v(TAG, "Mirroring navigation icons");
+ mBackButton.setRotation(IMAGE_MIRROR_ROTATION);
+ mCloseButton.setRotation(IMAGE_MIRROR_ROTATION);
+ }
+
+ if (showBackButton && showCloseButton) {
+ Log.w(TAG, "Showing Back and Close button simultaneously is not supported");
+ }
+
+ // Set the back button visibility based on the custom attribute.
setBackButtonVisible(showBackButton);
+ // Set the close button visibility based on the custom attribute.
+ setCloseButtonVisible(showCloseButton);
// Se the title bar.
setTitleBar(findViewById(R.id.application_bar));
@@ -242,19 +272,25 @@ class CarSetupWizardBaseLayout extends LinearLayout {
*/
@VisibleForTesting
void setViewVisible(View view, boolean visible) {
+ if (view == null) {
+ return;
+ }
view.setVisibility(visible ? View.VISIBLE : View.GONE);
}
// Add or remove the back button touch delegate depending on whether it is visible.
@VisibleForTesting
- void updateBackButtonTouchDelegate(boolean visible) {
+ void updateNavigationButtonTouchDelegate(View button, boolean visible) {
+ if (button == null) {
+ return;
+ }
if (visible) {
// Post this action in the parent's message queue to make sure the parent
// lays out its children before getHitRect() is called
this.post(() -> {
Rect delegateArea = new Rect();
- mBackButton.getHitRect(delegateArea);
+ button.getHitRect(delegateArea);
/*
* Update the delegate area based on the difference between the current size and
@@ -273,17 +309,16 @@ class CarSetupWizardBaseLayout extends LinearLayout {
delegateArea.top -= sizeDifference;
// Set the TouchDelegate on the parent view
- TouchDelegate touchDelegate = new TouchDelegate(delegateArea,
- mBackButton);
+ TouchDelegate touchDelegate = new TouchDelegate(delegateArea, button);
- if (View.class.isInstance(mBackButton.getParent())) {
- ((View) mBackButton.getParent()).setTouchDelegate(touchDelegate);
+ if (View.class.isInstance(button.getParent())) {
+ ((View) button.getParent()).setTouchDelegate(touchDelegate);
}
});
} else {
// Set the TouchDelegate to null if the back button is not visible.
- if (View.class.isInstance(mBackButton.getParent())) {
- ((View) mBackButton.getParent()).setTouchDelegate(null);
+ if (View.class.isInstance(button.getParent())) {
+ ((View) button.getParent()).setTouchDelegate(null);
}
}
}
@@ -312,8 +347,41 @@ class CarSetupWizardBaseLayout extends LinearLayout {
* Set the back button visibility to the given visibility.
*/
public void setBackButtonVisible(boolean visible) {
+ if (visible) {
+ setViewVisible(mCloseButton, false);
+ updateNavigationButtonTouchDelegate(mCloseButton, false);
+ }
setViewVisible(mBackButton, visible);
- updateBackButtonTouchDelegate(visible);
+ updateNavigationButtonTouchDelegate(mBackButton, visible);
+ }
+
+ public View getCloseButton() {
+ return mCloseButton;
+ }
+
+ @VisibleForTesting
+ final void setCloseButton(View closeButton) {
+ mCloseButton = closeButton;
+ }
+
+ /**
+ * Set the close button onClickListener to given listener. Can be null if the listener should
+ * be overridden so no callback is made.
+ */
+ public void setCloseButtonListener(@Nullable View.OnClickListener listener) {
+ mCloseButton.setOnClickListener(listener);
+ }
+
+ /**
+ * Set the back button visibility to the given visibility.
+ */
+ public void setCloseButtonVisible(boolean visible) {
+ if (visible) {
+ setViewVisible(mBackButton, false);
+ updateNavigationButtonTouchDelegate(mBackButton, false);
+ }
+ setViewVisible(mCloseButton, visible);
+ updateNavigationButtonTouchDelegate(mCloseButton, visible);
}
/**
@@ -519,7 +587,6 @@ class CarSetupWizardBaseLayout extends LinearLayout {
return;
}
int direction = TextUtils.getLayoutDirectionFromLocale(locale);
- setLayoutDirection(direction);
mToolbarTitle.setTextLocale(locale);
mToolbarTitle.setLayoutDirection(direction);
@@ -622,6 +689,15 @@ 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);
+ }
+
/** Sets button type face with partner overlay if exists */
private void setButtonTypeFace(TextView button) {
String fontFamily = mPartnerConfigHelper.getString(
diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java
index 2d74aa9..f5191cc 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayout.java
@@ -16,10 +16,11 @@
package com.android.car.setupwizardlib;
-import android.annotation.Nullable;
import android.content.Context;
import android.util.AttributeSet;
+import androidx.annotation.Nullable;
+
/**
* This layout applies light theming attributes from the partner overlay. It's functionally
* equivalent to CarSetupWizardBaseLayout which is package-private. But in the future, it could be
diff --git a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java
index 62e52d9..92269f0 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardDesignLayout.java
@@ -16,10 +16,11 @@
package com.android.car.setupwizardlib;
-import android.annotation.Nullable;
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 9d30220..19a1923 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardLayout.java
@@ -15,7 +15,6 @@
*/
package com.android.car.setupwizardlib;
-import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
@@ -40,6 +39,7 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
+import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.annotation.VisibleForTesting;
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 00c0ea3..54d1e6e 100644
--- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java
+++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfig.java
@@ -28,6 +28,12 @@ public enum PartnerConfig {
CONFIG_TOOLBAR_BUTTON_ICON_BACK(
PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_BACK, ResourceType.DRAWABLE),
+ CONFIG_TOOLBAR_BUTTON_ICON_CLOSE(
+ PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_CLOSE, ResourceType.DRAWABLE),
+
+ CONFIG_TOOLBAR_NAV_ICON_MIRRORING_IN_RTL(
+ PartnerConfigKey.KEY_TOOLBAR_NAV_BUTTON_MIRRORING_IN_RTL, ResourceType.BOOLEAN),
+
CONFIG_TOOLBAR_BUTTON_FONT_FAMILY(
PartnerConfigKey.KEY_TOOLBAR_BUTTON_FONT_FAMILY, ResourceType.STRING),
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 32caceb..7f9dadd 100644
--- a/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java
+++ b/library/main/src/com/android/car/setupwizardlib/partner/PartnerConfigKey.java
@@ -26,6 +26,8 @@ import java.lang.annotation.RetentionPolicy;
PartnerConfigKey.KEY_IMMERSIVE_MODE,
PartnerConfigKey.KEY_TOOLBAR_BG_COLOR,
PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_BACK,
+ PartnerConfigKey.KEY_TOOLBAR_BUTTON_ICON_CLOSE,
+ PartnerConfigKey.KEY_TOOLBAR_NAV_BUTTON_MIRRORING_IN_RTL,
PartnerConfigKey.KEY_TOOLBAR_BUTTON_FONT_FAMILY,
PartnerConfigKey.KEY_TOOLBAR_BUTTON_PADDING_HORIZONTAL,
PartnerConfigKey.KEY_TOOLBAR_BUTTON_PADDING_VERTICAL,
@@ -54,6 +56,11 @@ public @interface PartnerConfigKey {
String KEY_TOOLBAR_BUTTON_ICON_BACK = "suw_compat_toolbar_button_icon_back";
+ String KEY_TOOLBAR_BUTTON_ICON_CLOSE = "suw_compat_toolbar_button_icon_close";
+
+ String KEY_TOOLBAR_NAV_BUTTON_MIRRORING_IN_RTL =
+ "suw_compat_toolbar_nav_button_mirroring_in_rtl";
+
String KEY_TOOLBAR_BUTTON_FONT_FAMILY = "suw_compat_toolbar_button_font_family";
String KEY_TOOLBAR_BUTTON_TEXT_SIZE = "suw_compat_toolbar_button_text_size";
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 ed556cd..2dfb04b 100644
--- a/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java
+++ b/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java
@@ -17,7 +17,6 @@
package com.android.car.setupwizardlib.summary;
-import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +28,8 @@ 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;
@@ -85,14 +86,14 @@ public class PartnerSummaryActionsCollector {
ResolveInfo resolveInfo = getSummaryContentProviderResolveInfo(context.getPackageManager());
if (resolveInfo == null) {
- Log.e(TAG, "Could not find partner content provider, ignoring partner summary items.");
+ Log.i(TAG, "Could not find partner content provider, ignoring partner summary items.");
return;
}
mContentProviderUri = getSummaryContentProviderUri(resolveInfo);
if (mContentProviderUri == null) {
- Log.e(TAG, "Could not fetch content provider URI, ignoring partner summary items.");
+ Log.i(TAG, "Could not fetch content provider URI, ignoring partner summary items.");
}
}
@@ -309,7 +310,7 @@ public class PartnerSummaryActionsCollector {
if (deferredAction != null) {
deferredActions.add(deferredAction);
}
- } catch (NullPointerException e) {
+ } catch (NullPointerException | IllegalArgumentException e) {
Log.e(
TAG,
"Unable to load the completion or config state for deferred action: "
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 aac4ce7..6f9e626 100644
--- a/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java
+++ b/library/main/src/com/android/car/setupwizardlib/summary/SummaryAction.java
@@ -16,7 +16,7 @@
package com.android.car.setupwizardlib.summary;
-import android.annotation.NonNull;
+import androidx.annotation.NonNull;
/** An instance that represents a single summary action item and all of its state. */
public class SummaryAction implements Comparable<SummaryAction> {
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 759dd81..c58e352 100644
--- a/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java
+++ b/library/main/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitor.java
@@ -18,8 +18,13 @@ package com.android.car.setupwizardlib.util;
import android.car.Car;
import android.car.CarNotConnectedException;
+import android.car.VehicleAreaType;
+import android.car.VehicleGear;
+import android.car.VehiclePropertyIds;
import android.car.drivingstate.CarUxRestrictions;
import android.car.drivingstate.CarUxRestrictionsManager;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -43,11 +48,15 @@ public class CarDrivingStateMonitor implements
public static final String EXIT_BROADCAST_ACTION =
"com.android.car.setupwizardlib.driving_exit";
+ public static final String INTENT_EXTRA_REASON = "reason";
+ public static final String REASON_GEAR_REVERSAL = "gear_reversal";
+
private static final String TAG = "CarDrivingStateMonitor";
private static final long DISCONNECT_DELAY_MS = 700;
private Car mCar;
private CarUxRestrictionsManager mRestrictionsManager;
+ private CarPropertyManager mCarPropertyManager;
// Need to track the number of times the monitor is started so a single stopMonitor call does
// not override them all.
private int mMonitorStartedCount;
@@ -61,6 +70,25 @@ public class CarDrivingStateMonitor implements
@VisibleForTesting
final Runnable mDisconnectRunnable = this::disconnectCarMonitor;
+ private final CarPropertyManager.CarPropertyEventCallback mGearChangeCallback =
+ new CarPropertyManager.CarPropertyEventCallback() {
+ @SuppressWarnings("rawtypes")
+ @Override
+ public void onChangeEvent(CarPropertyValue value) {
+ switch (value.getPropertyId()) {
+ case VehiclePropertyIds.GEAR_SELECTION:
+ if ((Integer) value.getValue() == VehicleGear.GEAR_REVERSE) {
+ Log.v(TAG, "Gear has reversed, exiting SetupWizard.");
+ broadcastGearReversal();
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void onErrorEvent(int propertyId, int zone) {}
+ };
+
private CarDrivingStateMonitor(Context context) {
mContext = context.getApplicationContext();
}
@@ -79,14 +107,14 @@ public class CarDrivingStateMonitor implements
* Starts the monitor listening to driving state changes.
*/
public synchronized void startMonitor() {
- if (isVerboseLoggable()) {
- Log.v(TAG, "Starting monitor");
- }
mMonitorStartedCount++;
if (mMonitorStartedCount == 0) {
+ Log.w(TAG, "MonitorStartedCount was negative");
return;
}
mHandler.removeCallbacks(mDisconnectRunnable);
+ Log.i(TAG, String.format(
+ "Starting monitor, MonitorStartedCount = %d", mMonitorStartedCount));
if (mCar != null) {
if (mCar.isConnected()) {
try {
@@ -108,18 +136,9 @@ public class CarDrivingStateMonitor implements
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
- mRestrictionsManager = (CarUxRestrictionsManager)
- mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
- if (mRestrictionsManager == null) {
- Log.e(TAG, "Unable to get CarUxRestrictionsManager");
- return;
- }
- onUxRestrictionsChanged(mRestrictionsManager.getCurrentCarUxRestrictions());
- mRestrictionsManager.registerListener(CarDrivingStateMonitor.this);
- if (mStopMonitorAfterUxCheck) {
- mStopMonitorAfterUxCheck = false;
- stopMonitor();
- }
+ registerPropertyManager();
+ registerRestrictionsManager();
+
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car not connected", e);
}
@@ -169,17 +188,22 @@ public class CarDrivingStateMonitor implements
}
private void disconnectCarMonitor() {
- if (isVerboseLoggable()) {
- Log.v(TAG, "Timeout finished, disconnecting Car Monitor");
- }
if (mMonitorStartedCount > 0) {
+ if (isVerboseLoggable()) {
+ Log.v(TAG, "MonitorStartedCount > 0, do nothing");
+ }
return;
}
+ Log.i(TAG, "Disconnecting Car Monitor");
try {
if (mRestrictionsManager != null) {
mRestrictionsManager.unregisterListener();
mRestrictionsManager = null;
}
+ if (mCarPropertyManager != null) {
+ mCarPropertyManager.unregisterCallback(mGearChangeCallback);
+ mCarPropertyManager = null;
+ }
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car not connected for unregistering listener", e);
}
@@ -224,8 +248,18 @@ public class CarDrivingStateMonitor implements
}
private boolean checkIsSetupRestricted(@Nullable CarUxRestrictions restrictionInfo) {
- return restrictionInfo != null && (restrictionInfo.getActiveRestrictions()
- & CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP) != 0;
+ if (restrictionInfo == null) {
+ if (isVerboseLoggable()) {
+ Log.v(TAG, "checkIsSetupRestricted restrictionInfo is null, returning false");
+ }
+ return false;
+ }
+ int activeRestrictions = restrictionInfo.getActiveRestrictions();
+ if (isVerboseLoggable()) {
+ Log.v(TAG, "activeRestrictions are " + activeRestrictions);
+ }
+ // There must be at least some restriction in place.
+ return activeRestrictions != 0;
}
@Override
@@ -274,4 +308,49 @@ public class CarDrivingStateMonitor implements
public static void replace(Context context, CarDrivingStateMonitor monitor) {
CarHelperRegistry.getRegistry(context).putHelper(CarDrivingStateMonitor.class, monitor);
}
+
+ private void registerRestrictionsManager() {
+ mRestrictionsManager = (CarUxRestrictionsManager)
+ mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+ if (mRestrictionsManager == null) {
+ Log.e(TAG, "Unable to get CarUxRestrictionsManager");
+ return;
+ }
+ onUxRestrictionsChanged(mRestrictionsManager.getCurrentCarUxRestrictions());
+ mRestrictionsManager.registerListener(CarDrivingStateMonitor.this);
+ if (mStopMonitorAfterUxCheck) {
+ mStopMonitorAfterUxCheck = false;
+ stopMonitor();
+ }
+ }
+
+ private void registerPropertyManager() {
+ mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
+ if (mCarPropertyManager == null) {
+ Log.e(TAG, "Unable to get CarPropertyManager");
+ return;
+ }
+ mCarPropertyManager.registerCallback(
+ mGearChangeCallback, VehiclePropertyIds.GEAR_SELECTION,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE);
+ CarPropertyValue<Integer> gearSelection =
+ mCarPropertyManager.getProperty(Integer.class, VehiclePropertyIds.GEAR_SELECTION,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
+ if (gearSelection != null
+ && gearSelection.getStatus() == CarPropertyValue.STATUS_AVAILABLE) {
+ if (gearSelection.getValue() == VehicleGear.GEAR_REVERSE) {
+ Log.v(TAG, "SetupWizard started when gear is in reverse, exiting.");
+ broadcastGearReversal();
+ }
+ } else {
+ Log.e(TAG, "GEAR_SELECTION is not available.");
+ }
+ }
+
+ private void broadcastGearReversal() {
+ Intent intent = new Intent();
+ intent.setAction(EXIT_BROADCAST_ACTION);
+ intent.putExtra(INTENT_EXTRA_REASON, REASON_GEAR_REVERSAL);
+ mContext.sendBroadcast(intent);
+ }
}
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 3611931..4e1d8ca 100644
--- a/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java
+++ b/library/main/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtils.java
@@ -31,9 +31,13 @@ import androidx.core.util.Preconditions;
public final class CarSetupWizardUiUtils {
private static final String TAG = CarSetupWizardUiUtils.class.getSimpleName();
- /** Key for immersive mode value pased to 1P apps */
+ /** Key for immersive mode value passed to 1P apps */
public static final String IMMERSIVE_MODE_TYPE = "immersiveModeType";
+ /** Key indicating whether 1P apps should switch to the new landscape design */
+ public static final String EXTRA_NEW_LANDSCAPE_LAYOUT_SUPPORTED =
+ "extra_new_landscape_layout_supported";
+
/** 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 7f5cf7a..ff83b55 100644
--- a/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java
+++ b/library/main/src/com/android/car/setupwizardlib/util/CarWizardManagerHelper.java
@@ -148,4 +148,25 @@ public final class CarWizardManagerHelper {
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 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);
+ }
}
diff --git a/library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java b/library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java
index 604e8b0..89b8d11 100644
--- a/library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java
+++ b/library/main/src/com/android/car/setupwizardlib/util/ResultCodes.java
@@ -23,7 +23,11 @@ import static android.app.Activity.RESULT_FIRST_USER;
*/
public final class ResultCodes {
public static final int RESULT_SKIP = RESULT_FIRST_USER;
+ public static final int RESULT_RETRY = RESULT_FIRST_USER + 1;
public static final int RESULT_ACTIVITY_NOT_FOUND = RESULT_FIRST_USER + 2;
+ public static final int RESULT_LIFECYCLE_NOT_MATCHED = RESULT_FIRST_USER + 3;
+ public static final int RESULT_FLOW_NOT_MATCHED = RESULT_FIRST_USER + 4;
+
public static final int RESULT_FIRST_SETUP_USER = RESULT_FIRST_USER + 100;
private ResultCodes() {
diff --git a/library/main/tests/robotests/Android.bp b/library/main/tests/robotests/Android.bp
index 13335f3..d5cf533 100644
--- a/library/main/tests/robotests/Android.bp
+++ b/library/main/tests/robotests/Android.bp
@@ -1,6 +1,10 @@
//##############################################################
// CarSetupWizardLib app just for Robolectric test target. #
//##############################################################
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
android_app {
name: "CarSetupWizardLib",
diff --git a/library/main/tests/robotests/AndroidManifest.xml b/library/main/tests/robotests/AndroidManifest.xml
index a0b00ba..4471c50 100644
--- a/library/main/tests/robotests/AndroidManifest.xml
+++ b/library/main/tests/robotests/AndroidManifest.xml
@@ -16,6 +16,6 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.car.setupwizardlib.robotests">
+ package="com.android.car.setupwizardlib.test">
</manifest>
diff --git a/library/main/tests/robotests/res/values/attrs.xml b/library/main/tests/robotests/res/values/attrs.xml
index 4454939..0591552 100644
--- a/library/main/tests/robotests/res/values/attrs.xml
+++ b/library/main/tests/robotests/res/values/attrs.xml
@@ -19,6 +19,8 @@
<declare-styleable name="CarSetupWizardBaseLayout">
<!-- Attributes related to the visibility of the back button -->
<attr name="showBackButton" format="boolean"/>
+ <!-- Attributes related to the visibility of the close button -->
+ <attr name="showCloseButton" format="boolean"/>
<!-- Attributes related to the visibility and text of the toolbar title -->
<attr name="showToolbarTitle" format="boolean"/>
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 632ed6d..7209fc9 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
@@ -38,6 +38,7 @@ 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;
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 6ec0c28..3ed02c0 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
@@ -37,6 +37,7 @@ 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.robolectric.TestHelper;
+import com.android.car.setupwizardlib.shadows.ShadowConfiguration;
import org.junit.Before;
import org.junit.Test;
@@ -45,6 +46,7 @@ import org.mockito.Mockito;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowTextView;
import org.robolectric.util.ReflectionHelpers;
@@ -56,6 +58,7 @@ import java.util.Locale;
* Tests for the CarSetupWizardCompatLayout
*/
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowConfiguration.class)
public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
private static final Locale LOCALE_EN_US = new Locale("en", "US");
// Hebrew locale can be used to test RTL.
@@ -101,8 +104,22 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
}
/**
+ * Test that {@link CarSetupWizardCompatLayout#setCloseButtonListener} does set the close button
+ * listener.
+ */
+ @Test
+ public void testSetCloseButtonListener() {
+ View.OnClickListener spyListener = TestHelper.createSpyListener();
+
+ mCarSetupWizardCompatLayout.setCloseButtonListener(spyListener);
+ mCarSetupWizardCompatLayout.getCloseButton().performClick();
+ Mockito.verify(spyListener).onClick(mCarSetupWizardCompatLayout.getCloseButton());
+ }
+
+ /**
* Test that {@link CarSetupWizardCompatLayout#setBackButtonVisible} does set the view
- * visible/not visible and calls updateBackButtonTouchDelegate.
+ * visible/not visible and calls
+ * {@link CarSetupWizardDesignLayout#updateNavigationButtonTouchDelegate(View, boolean)}.
*/
@Test
public void testSetBackButtonVisibleTrue() {
@@ -112,12 +129,18 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
spyCarSetupWizardCompatLayout.setBackButtonVisible(true);
View backButton = spyCarSetupWizardCompatLayout.getBackButton();
TestHelper.assertViewVisible(backButton);
- Mockito.verify(spyCarSetupWizardCompatLayout).updateBackButtonTouchDelegate(true);
+ Mockito.verify(spyCarSetupWizardCompatLayout)
+ .updateNavigationButtonTouchDelegate(backButton, true);
+ View closeButton = spyCarSetupWizardCompatLayout.getCloseButton();
+ TestHelper.assertViewNotVisible(closeButton);
+ Mockito.verify(spyCarSetupWizardCompatLayout)
+ .updateNavigationButtonTouchDelegate(closeButton, false);
}
/**
* Test that {@link CarSetupWizardCompatLayout#setBackButtonVisible} does set the view
- * visible/not visible and calls updateBackButtonTouchDelegate.
+ * visible/not visible and calls
+ * {@link CarSetupWizardDesignLayout#updateNavigationButtonTouchDelegate(View, boolean)}.
*/
@Test
public void testSetBackButtonVisibleFalse() {
@@ -127,7 +150,47 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
spyCarSetupWizardCompatLayout.setBackButtonVisible(false);
View backButton = spyCarSetupWizardCompatLayout.getBackButton();
TestHelper.assertViewNotVisible(backButton);
- Mockito.verify(spyCarSetupWizardCompatLayout).updateBackButtonTouchDelegate(false);
+ Mockito.verify(spyCarSetupWizardCompatLayout)
+ .updateNavigationButtonTouchDelegate(backButton, false);
+ }
+
+ /**
+ * Test that {@link CarSetupWizardCompatLayout#setCloseButtonVisible} does set the view
+ * visible/not visible and calls
+ * {@link CarSetupWizardDesignLayout#updateNavigationButtonTouchDelegate(View, boolean)}.
+ */
+ @Test
+ public void testSetCloseButtonVisibleTrue() {
+ CarSetupWizardCompatLayout spyCarSetupWizardCompatLayout =
+ Mockito.spy(mCarSetupWizardCompatLayout);
+
+ spyCarSetupWizardCompatLayout.setCloseButtonVisible(true);
+ View closeButton = spyCarSetupWizardCompatLayout.getCloseButton();
+ TestHelper.assertViewVisible(closeButton);
+ Mockito.verify(spyCarSetupWizardCompatLayout)
+ .updateNavigationButtonTouchDelegate(closeButton, true);
+ View backButton = spyCarSetupWizardCompatLayout.getBackButton();
+ TestHelper.assertViewNotVisible(backButton);
+ Mockito.verify(spyCarSetupWizardCompatLayout)
+ .updateNavigationButtonTouchDelegate(backButton, false);
+ }
+
+
+ /**
+ * Test that {@link CarSetupWizardCompatLayout#setCloseButtonVisible} does set the view
+ * visible/not visible and calls
+ * {@link CarSetupWizardDesignLayout#updateNavigationButtonTouchDelegate(View, boolean)}.
+ */
+ @Test
+ public void testSetCloseButtonVisibleFalse() {
+ CarSetupWizardCompatLayout spyCarSetupWizardCompatLayout =
+ Mockito.spy(mCarSetupWizardCompatLayout);
+
+ spyCarSetupWizardCompatLayout.setCloseButtonVisible(false);
+ View closeButton = spyCarSetupWizardCompatLayout.getCloseButton();
+ TestHelper.assertViewNotVisible(closeButton);
+ Mockito.verify(spyCarSetupWizardCompatLayout)
+ .updateNavigationButtonTouchDelegate(closeButton, false);
}
/**
@@ -532,6 +595,30 @@ public class CarSetupWizardCompatLayoutTest extends BaseRobolectricTest {
assertThat(secondaryButton.getTextSize()).isWithin(TOLERANCE).of(EXCEPTED_TEXT_SIZE);
}
+ @Test
+ public void test_shouldNotMirrorNavIcons_inLtr() {
+ Activity activity = Robolectric.buildActivity(CarSetupWizardLayoutTestActivity.class)
+ .create()
+ .get();
+
+ CarSetupWizardCompatLayout layout = activity.findViewById(R.id.car_setup_wizard_layout);
+ assertThat(layout.shouldMirrorNavIcons()).isFalse();
+ }
+
+ @Test
+ public void test_shouldMirrorNavIcons_inRtl() {
+ application.getResources().getConfiguration().setLocale(LOCALE_IW_IL);
+
+ Activity activity = Robolectric.buildActivity(CarSetupWizardLayoutTestActivity.class)
+ .create()
+ .get();
+
+ 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(layout.shouldMirrorNavIcons()).isTrue();
+ }
+
private void setupFakeContentProvider() {
FakeOverrideContentProvider.installDefaultProvider();
}
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutAlternativeActivity.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutAlternativeActivity.java
index b20da7c..8fbe9e4 100644
--- a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutAlternativeActivity.java
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutAlternativeActivity.java
@@ -19,6 +19,8 @@ package com.android.car.setupwizardlib;
import android.app.Activity;
import android.os.Bundle;
+import com.android.car.setupwizardlib.test.R;
+
/**
* Activity for CarSetupWizardLayoutTest where primary button isn't shown but secondary button is.
*/
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutTestActivity.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutTestActivity.java
index 1894933..6350c44 100644
--- a/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutTestActivity.java
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardLayoutTestActivity.java
@@ -19,6 +19,8 @@ package com.android.car.setupwizardlib;
import android.app.Activity;
import android.os.Bundle;
+import com.android.car.setupwizardlib.test.R;
+
/**
* Activity for CarSetupWizardLayoutTest
*/
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/shadows/ShadowConfiguration.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/shadows/ShadowConfiguration.java
new file mode 100644
index 0000000..39057be
--- /dev/null
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/shadows/ShadowConfiguration.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.setupwizardlib.shadows;
+
+import android.content.res.Configuration;
+import android.view.View;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.Locale;
+
+/**
+ * Shadow class for {@link Configuration}.
+ */
+@Implements(Configuration.class)
+public class ShadowConfiguration {
+
+ private static final Locale HEBREW_LOCALE = new Locale("iw", "IL");
+ private int mLayoutDir = View.LAYOUT_DIRECTION_LTR;
+
+ /**
+ * Set the layout direction from a {@link Locale}.
+ */
+ @Implementation
+ public void setLayoutDirection(Locale locale) {
+ if (locale.getLanguage().equals(HEBREW_LOCALE.getLanguage())) {
+ mLayoutDir = View.LAYOUT_DIRECTION_RTL;
+ }
+ }
+
+ /** Returs the layout direction */
+ @Implementation
+ public int getLayoutDirection() {
+ return mLayoutDir;
+ }
+}
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitorTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitorTest.java
index 0afc469..afa28f9 100644
--- a/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitorTest.java
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarDrivingStateMonitorTest.java
@@ -127,12 +127,32 @@ public class CarDrivingStateMonitorTest extends BaseRobolectricTest {
}
@Test
+ public void testOnUxRestrictionsChangedForNonSetup_triggersExit() {
+ mCarDrivingStateMonitor.startMonitor();
+ doReturn(CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO).when(mMockRestrictions)
+ .getActiveRestrictions();
+ mCarDrivingStateMonitor.onUxRestrictionsChanged(mMockRestrictions);
+ assertThat(mShadowApplication.getBroadcastIntents().get(0).getAction())
+ .isEqualTo(CarDrivingStateMonitor.EXIT_BROADCAST_ACTION);
+ }
+
+ @Test
+ public void testStartMonitorWhileDrivingForNonSetup_triggersExit() {
+ doReturn(CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO).when(mMockRestrictions)
+ .getActiveRestrictions();
+ mCarDrivingStateMonitor.startMonitor();
+ assertThat(mShadowApplication.getBroadcastIntents().get(0).getAction())
+ .isEqualTo(CarDrivingStateMonitor.EXIT_BROADCAST_ACTION);
+ }
+
+ @Test
public void testStartMonitor_clearsStopMonitorRunnable() {
mCarDrivingStateMonitor.startMonitor();
ShadowCar.setIsConnected(true);
mCarDrivingStateMonitor.stopMonitor();
mCarDrivingStateMonitor.startMonitor();
- assertThat(mCarDrivingStateMonitor.mHandler.hasMessagesOrCallbacks()).isFalse();
+ assertThat(mCarDrivingStateMonitor.mHandler
+ .hasCallbacks(mCarDrivingStateMonitor.mDisconnectRunnable)).isFalse();
}
@Test
diff --git a/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtilsTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtilsTest.java
index 5933bd4..bacb77a 100644
--- a/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtilsTest.java
+++ b/library/main/tests/robotests/src/com/android/car/setupwizardlib/util/CarSetupWizardUiUtilsTest.java
@@ -23,7 +23,7 @@ import android.graphics.Color;
import android.view.View;
import android.view.Window;
-import com.android.car.setupwizardlib.robotests.R;
+import com.android.car.setupwizardlib.test.R;
import org.junit.Before;
import org.junit.Test;
@@ -56,8 +56,8 @@ public class CarSetupWizardUiUtilsTest {
// Note that these colors are defined in the test theme
private static final int TEST_THEME = R.style.NavAndStatusBarTestTheme;
- private static final int EXPECTED_COLOR_STATUS_BAR = Color.getHtmlColor("#001");
- private static final int EXPECTED_COLOR_NAVIGATION_BAR = Color.getHtmlColor("#002");
+ private static final int EXPECTED_COLOR_STATUS_BAR = Integer.decode("#001");
+ private static final int EXPECTED_COLOR_NAVIGATION_BAR = Integer.decode("#002");
private Activity mActivity;
private Window mWindow;
diff --git a/library/utils/Android.bp b/library/utils/Android.bp
index 7cd7c0b..f4b5bd9 100644
--- a/library/utils/Android.bp
+++ b/library/utils/Android.bp
@@ -13,6 +13,10 @@
// limitations under the License.
//
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
android_library {
name: "car-setup-wizard-lib-utils",
srcs: ["src/**/*.java",
diff --git a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java
index 4ef851e..6c7830f 100644
--- a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java
+++ b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupClient.java
@@ -16,11 +16,13 @@
package com.android.car.setupwizardlib;
+import android.app.KeyguardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -28,6 +30,7 @@ import android.os.RemoteException;
import android.util.Log;
import com.android.car.setupwizardlib.InitialLockSetupConstants.LockTypes;
+import com.android.car.setupwizardlib.InitialLockSetupConstants.PasswordComplexity;
import com.android.car.setupwizardlib.InitialLockSetupConstants.SetLockCodes;
import com.android.car.setupwizardlib.InitialLockSetupConstants.ValidateLockFlags;
@@ -56,6 +59,7 @@ public class InitialLockSetupClient implements ServiceConnection {
private InitialLockListener mInitialLockListener;
private Context mContext;
+ private KeyguardManager mKeyguardManager;
private IInitialLockSetupService mInitialLockSetupService;
private ValidateLockAsyncTask mCurrentValidateLockTask;
private SaveLockAsyncTask mCurrentSaveLockTask;
@@ -65,6 +69,7 @@ public class InitialLockSetupClient implements ServiceConnection {
public InitialLockSetupClient(Context context) {
mContext = context.getApplicationContext();
+ mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
}
/**
@@ -120,8 +125,8 @@ public class InitialLockSetupClient implements ServiceConnection {
* Fetches the set of {@link LockConfig}s that define the lock constraints for the device.
*/
public void getLockConfigs() {
- LockConfigsAsyncTask lockConfigsAsyncTask = new LockConfigsAsyncTask(mInitialLockListener,
- mInitialLockSetupService);
+ LockConfigsAsyncTask lockConfigsAsyncTask = new LockConfigsAsyncTask(
+ mInitialLockListener, mInitialLockSetupService, mKeyguardManager);
lockConfigsAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);
}
@@ -136,8 +141,8 @@ public class InitialLockSetupClient implements ServiceConnection {
&& mCurrentValidateLockTask.getStatus() != AsyncTask.Status.FINISHED) {
mCurrentValidateLockTask.cancel(true);
}
- mCurrentValidateLockTask = new ValidateLockAsyncTask(
- mInitialLockListener, mInitialLockSetupService, LockTypes.PASSWORD);
+ mCurrentValidateLockTask = new ValidateLockAsyncTask(mInitialLockListener,
+ mInitialLockSetupService, mKeyguardManager, LockTypes.PASSWORD);
mCurrentValidateLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, password);
}
@@ -151,8 +156,8 @@ public class InitialLockSetupClient implements ServiceConnection {
&& mCurrentValidateLockTask.getStatus() != AsyncTask.Status.FINISHED) {
mCurrentValidateLockTask.cancel(true);
}
- mCurrentValidateLockTask = new ValidateLockAsyncTask(
- mInitialLockListener, mInitialLockSetupService, LockTypes.PIN);
+ mCurrentValidateLockTask = new ValidateLockAsyncTask(mInitialLockListener,
+ mInitialLockSetupService, mKeyguardManager, LockTypes.PIN);
mCurrentValidateLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pin);
}
@@ -166,8 +171,8 @@ public class InitialLockSetupClient implements ServiceConnection {
&& mCurrentValidateLockTask.getStatus() != AsyncTask.Status.FINISHED) {
mCurrentValidateLockTask.cancel(true);
}
- mCurrentValidateLockTask = new ValidateLockAsyncTask(
- mInitialLockListener, mInitialLockSetupService, LockTypes.PATTERN);
+ mCurrentValidateLockTask = new ValidateLockAsyncTask(mInitialLockListener,
+ mInitialLockSetupService, mKeyguardManager, LockTypes.PATTERN);
mCurrentValidateLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pattern);
}
@@ -184,7 +189,7 @@ public class InitialLockSetupClient implements ServiceConnection {
return;
}
mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener,
- mInitialLockSetupService, LockTypes.PASSWORD);
+ mInitialLockSetupService, mKeyguardManager, LockTypes.PASSWORD);
mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, password);
}
@@ -200,7 +205,7 @@ public class InitialLockSetupClient implements ServiceConnection {
return;
}
mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener,
- mInitialLockSetupService, LockTypes.PIN);
+ mInitialLockSetupService, mKeyguardManager, LockTypes.PIN);
mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pin);
}
@@ -217,7 +222,7 @@ public class InitialLockSetupClient implements ServiceConnection {
return;
}
mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener,
- mInitialLockSetupService, LockTypes.PATTERN);
+ mInitialLockSetupService, mKeyguardManager, LockTypes.PATTERN);
mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pattern);
}
@@ -282,29 +287,56 @@ public class InitialLockSetupClient implements ServiceConnection {
private WeakReference<InitialLockListener> mInitialLockListener;
private WeakReference<IInitialLockSetupService> mInitialLockSetupService;
+ private WeakReference<KeyguardManager> mKeyguardManager;
LockConfigsAsyncTask(InitialLockListener initialLockListener,
- IInitialLockSetupService initialLockSetupService) {
+ IInitialLockSetupService initialLockSetupService,
+ KeyguardManager keyguardManager) {
mInitialLockListener = new WeakReference<>(initialLockListener);
mInitialLockSetupService = new WeakReference<>(initialLockSetupService);
+ mKeyguardManager = new WeakReference<>(keyguardManager);
}
@Override
protected Map<Integer, LockConfig> doInBackground(Void... voids) {
- IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get();
- if (initialLockSetupService == null) {
- InitialLockSetupClient.logVerbose(
- "Lost reference to service in LockConfigsAsyncTask");
- return null;
- }
LockConfig passwordConfig, pinConfig, patternConfig;
- try {
- passwordConfig = initialLockSetupService.getLockConfig(LockTypes.PASSWORD);
- pinConfig = initialLockSetupService.getLockConfig(LockTypes.PIN);
- patternConfig = initialLockSetupService.getLockConfig(LockTypes.PATTERN);
- } catch (RemoteException e) {
- e.printStackTrace();
- return null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ KeyguardManager km = mKeyguardManager.get();
+ if (km == null) {
+ InitialLockSetupClient.logVerbose(
+ "Lost reference to keyguardManager in LockConfigsAsyncTask");
+ return null;
+ }
+ passwordConfig =
+ new LockConfig(
+ /* enabled= */ true,
+ km.getMinLockLength(
+ /* isPin= */ false, PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM));
+ pinConfig =
+ new LockConfig(
+ /* enabled= */ true,
+ km.getMinLockLength(
+ /* isPin= */ true, PasswordComplexity.PASSWORD_COMPLEXITY_LOW));
+ patternConfig =
+ new LockConfig(
+ /* enabled= */ true,
+ km.getMinLockLength(
+ /* isPin= */ false, PasswordComplexity.PASSWORD_COMPLEXITY_LOW));
+ } else {
+ IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get();
+ if (initialLockSetupService == null) {
+ InitialLockSetupClient.logVerbose(
+ "Lost reference to service in LockConfigsAsyncTask");
+ return null;
+ }
+ try {
+ passwordConfig = initialLockSetupService.getLockConfig(LockTypes.PASSWORD);
+ pinConfig = initialLockSetupService.getLockConfig(LockTypes.PIN);
+ patternConfig = initialLockSetupService.getLockConfig(LockTypes.PATTERN);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return null;
+ }
}
Map<Integer, LockConfig> map = new HashMap<>();
map.put(LockTypes.PASSWORD, passwordConfig);
@@ -327,32 +359,64 @@ public class InitialLockSetupClient implements ServiceConnection {
private WeakReference<InitialLockListener> mInitialLockListener;
private WeakReference<IInitialLockSetupService> mInitialLockSetupService;
+ private WeakReference<KeyguardManager> mKeyguardManager;
private int mLockType;
ValidateLockAsyncTask(
InitialLockListener initialLockListener,
IInitialLockSetupService initialLockSetupService,
+ KeyguardManager keyguardManager,
@LockTypes int lockType) {
mInitialLockListener = new WeakReference<>(initialLockListener);
mInitialLockSetupService = new WeakReference<>(initialLockSetupService);
+ mKeyguardManager = new WeakReference<>(keyguardManager);
mLockType = lockType;
}
@Override
protected Integer doInBackground(byte[]... passwords) {
InitialLockSetupClient.logVerbose("ValidateLockAsyncTask doInBackground");
- IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get();
- if (initialLockSetupService == null) {
- InitialLockSetupClient.logVerbose(
- "Lost reference to service in ValidateLockAsyncTask");
- return ValidateLockFlags.INVALID_GENERIC;
- }
- try {
- int output = initialLockSetupService.checkValidLock(mLockType, passwords[0]);
- return output;
- } catch (RemoteException e) {
- e.printStackTrace();
- return ValidateLockFlags.INVALID_GENERIC;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ KeyguardManager km = mKeyguardManager.get();
+ if (km == null) {
+ InitialLockSetupClient.logVerbose(
+ "Lost reference to keyguardManager in LockConfigsAsyncTask");
+ return null;
+ }
+ int complexity;
+ switch (mLockType) {
+ case LockTypes.PASSWORD:
+ complexity = PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM;
+ break;
+ case LockTypes.PIN:
+ complexity = PasswordComplexity.PASSWORD_COMPLEXITY_LOW;
+ break;
+ case LockTypes.PATTERN:
+ complexity = PasswordComplexity.PASSWORD_COMPLEXITY_LOW;
+ passwords[0] =
+ InitialLockSetupHelper.getNumericEquivalentByteArray(passwords[0]);
+ break;
+ default:
+ Log.e(TAG, "other lock type, returning generic error");
+ return ValidateLockFlags.INVALID_GENERIC;
+ }
+ return km.isValidLockPasswordComplexity(mLockType, passwords[0], complexity)
+ ? 0
+ : ValidateLockFlags.INVALID_GENERIC;
+ } else {
+ IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get();
+ if (initialLockSetupService == null) {
+ InitialLockSetupClient.logVerbose(
+ "Lost reference to service in ValidateLockAsyncTask");
+ return ValidateLockFlags.INVALID_GENERIC;
+ }
+ try {
+ int output = initialLockSetupService.checkValidLock(mLockType, passwords[0]);
+ return output;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return ValidateLockFlags.INVALID_GENERIC;
+ }
}
}
@@ -373,32 +437,64 @@ public class InitialLockSetupClient implements ServiceConnection {
private WeakReference<InitialLockListener> mInitialLockListener;
private WeakReference<IInitialLockSetupService> mInitialLockSetupService;
+ private WeakReference<KeyguardManager> mKeyguardManager;
private int mLockType;
SaveLockAsyncTask(
InitialLockListener initialLockListener,
IInitialLockSetupService initialLockSetupService,
+ KeyguardManager keyguardManager,
@LockTypes int lockType) {
mInitialLockListener = new WeakReference<>(initialLockListener);
mInitialLockSetupService = new WeakReference<>(initialLockSetupService);
+ mKeyguardManager = new WeakReference<>(keyguardManager);
mLockType = lockType;
}
@Override
protected Integer doInBackground(byte[]... passwords) {
InitialLockSetupClient.logVerbose("SaveLockAsyncTask doInBackground");
- IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get();
- if (initialLockSetupService == null) {
- InitialLockSetupClient.logVerbose(
- "Lost reference to service in SaveLockAsyncTask");
- return SetLockCodes.FAIL_LOCK_GENERIC;
- }
- try {
- int output = initialLockSetupService.setLock(mLockType, passwords[0]);
- return output;
- } catch (RemoteException e) {
- e.printStackTrace();
- return SetLockCodes.FAIL_LOCK_GENERIC;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ KeyguardManager km = mKeyguardManager.get();
+ if (km == null) {
+ InitialLockSetupClient.logVerbose(
+ "Lost reference to keyguardManager in SaveLockAsyncTask");
+ return null;
+ }
+ int complexity;
+ switch (mLockType) {
+ case LockTypes.PASSWORD:
+ complexity = PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM;
+ break;
+ case LockTypes.PIN:
+ complexity = PasswordComplexity.PASSWORD_COMPLEXITY_LOW;
+ break;
+ case LockTypes.PATTERN:
+ complexity = PasswordComplexity.PASSWORD_COMPLEXITY_LOW;
+ passwords[0] =
+ InitialLockSetupHelper.getNumericEquivalentByteArray(passwords[0]);
+ break;
+ default:
+ Log.e(TAG, "other lock type, returning generic error");
+ return SetLockCodes.FAIL_LOCK_GENERIC;
+ }
+ return km.setLock(mLockType, passwords[0], complexity)
+ ? 1
+ : SetLockCodes.FAIL_LOCK_GENERIC;
+ } else {
+ IInitialLockSetupService initialLockSetupService = mInitialLockSetupService.get();
+ if (initialLockSetupService == null) {
+ InitialLockSetupClient.logVerbose(
+ "Lost reference to service in SaveLockAsyncTask");
+ return SetLockCodes.FAIL_LOCK_GENERIC;
+ }
+ try {
+ int output = initialLockSetupService.setLock(mLockType, passwords[0]);
+ return output;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return SetLockCodes.FAIL_LOCK_GENERIC;
+ }
}
}
diff --git a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java
index 7081e78..8ca5c6e 100644
--- a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java
+++ b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupConstants.java
@@ -36,12 +36,14 @@ public interface InitialLockSetupConstants {
@IntDef({
LockTypes.PASSWORD,
LockTypes.PIN,
- LockTypes.PATTERN
+ LockTypes.PATTERN,
+ LockTypes.NONE
})
@interface LockTypes {
int PASSWORD = 0;
int PIN = 1;
int PATTERN = 2;
+ int NONE = 3;
}
/**
@@ -75,5 +77,19 @@ public interface InitialLockSetupConstants {
int FAIL_LOCK_INVALID = -2;
int FAIL_LOCK_GENERIC = -3;
}
+
+ /** PasswordComplexity as defined in DevicePolicyManager. */
+ @IntDef({
+ PasswordComplexity.PASSWORD_COMPLEXITY_NONE,
+ PasswordComplexity.PASSWORD_COMPLEXITY_LOW,
+ PasswordComplexity.PASSWORD_COMPLEXITY_MEDIUM,
+ PasswordComplexity.PASSWORD_COMPLEXITY_HIGH,
+ })
+ @interface PasswordComplexity {
+ int PASSWORD_COMPLEXITY_NONE = 0;
+ int PASSWORD_COMPLEXITY_LOW = 0x10000;
+ int PASSWORD_COMPLEXITY_MEDIUM = 0x30000;
+ int PASSWORD_COMPLEXITY_HIGH = 0x50000;
+ }
}
diff --git a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java
index 9820680..191ddbc 100644
--- a/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java
+++ b/library/utils/src/com/android/car/setupwizardlib/InitialLockSetupHelper.java
@@ -81,4 +81,13 @@ public class InitialLockSetupHelper {
}
return charSequence;
}
+
+ /** Return an ASCII-equivalent array of character digits for a numeric byte input. */
+ public static byte[] getNumericEquivalentByteArray(byte[] input) {
+ byte[] output = new byte[input.length];
+ for (int i = 0; i < input.length; i++) {
+ output[i] = (byte) (input[i] + 48);
+ }
+ return output;
+ }
}