Merge Android 12

Bug: 202323961
Merged-In: I08740b2e36340d196b0a64d1ab75ae2d3541b603
Change-Id: I90f3deb9857825eaa3bae14e935b96fbfb9a37dd
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/attrs.xml b/library/main/res/values/attrs.xml
index 74bb14e..31d2f5b 100644
--- a/library/main/res/values/attrs.xml
+++ b/library/main/res/values/attrs.xml
@@ -68,6 +68,8 @@
     <declare-styleable name="CarSetupWizardBaseLayout">
         <!-- Attributes related to the visibility of the back button -->
         <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"/>
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/BaseSetupWizardActivity.java b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
index a2fdff3..36caae0 100644
--- a/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
+++ b/library/main/src/com/android/car/setupwizardlib/BaseSetupWizardActivity.java
@@ -97,6 +97,8 @@
             }
         });
 
+        mCarSetupWizardLayout.setCloseButtonListener(v-> handleCloseButton());
+
         resetPrimaryToolbarButtonOnClickListener();
         resetSecondaryToolbarButtonOnClickListener();
 
@@ -255,6 +257,14 @@
     }
 
     /**
+     * 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 @@
     }
 
     /**
+     * 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 43d300e..715315a 100644
--- a/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java
+++ b/library/main/src/com/android/car/setupwizardlib/CarSetupWizardBaseLayout.java
@@ -63,6 +63,7 @@
     private static final float IMAGE_MIRROR_ROTATION = 180.0f;
 
     private View mBackButton;
+    private View mCloseButton;
     private View mTitleBar;
     private TextView mToolbarTitle;
     private PartnerConfigHelper mPartnerConfigHelper;
@@ -120,6 +121,7 @@
      */
     private void init(TypedArray attrArray) {
         boolean showBackButton;
+        boolean showCloseButton;
 
         boolean showToolbarTitle;
         String toolbarTitleText;
@@ -138,6 +140,8 @@
         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(
@@ -171,18 +175,34 @@
         toolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
 
         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));
@@ -252,19 +272,25 @@
      */
     @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
@@ -283,17 +309,16 @@
                 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);
             }
         }
     }
@@ -322,8 +347,41 @@
      * 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);
     }
 
     /**
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 27ea753..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,9 @@
     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),
 
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 8556fa7..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,7 @@
         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,
@@ -55,6 +56,8 @@
 
     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";
 
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 ebf0d35..2dfb04b 100644
--- a/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java
+++ b/library/main/src/com/android/car/setupwizardlib/summary/PartnerSummaryActionsCollector.java
@@ -86,14 +86,14 @@
         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.");
         }
     }
 
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 @@
         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 @@
  */
 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/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/CarSetupWizardCompatLayoutTest.java b/library/main/tests/robotests/src/com/android/car/setupwizardlib/CarSetupWizardCompatLayoutTest.java
index 541cf4c..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
@@ -104,8 +104,22 @@
     }
 
     /**
+     * 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() {
@@ -115,12 +129,18 @@
         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() {
@@ -130,7 +150,47 @@
         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);
     }
 
     /**
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.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 @@
 
     private InitialLockListener mInitialLockListener;
     private Context mContext;
+    private KeyguardManager mKeyguardManager;
     private IInitialLockSetupService mInitialLockSetupService;
     private ValidateLockAsyncTask mCurrentValidateLockTask;
     private SaveLockAsyncTask mCurrentSaveLockTask;
@@ -65,6 +69,7 @@
 
     public InitialLockSetupClient(Context context) {
         mContext = context.getApplicationContext();
+        mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
     }
 
     /**
@@ -120,8 +125,8 @@
      * 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 @@
                 && 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 @@
                 && 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 @@
                 && 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 @@
             return;
         }
         mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener,
-                mInitialLockSetupService, LockTypes.PASSWORD);
+                mInitialLockSetupService, mKeyguardManager, LockTypes.PASSWORD);
         mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, password);
     }
 
@@ -200,7 +205,7 @@
             return;
         }
         mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener,
-                mInitialLockSetupService, LockTypes.PIN);
+                mInitialLockSetupService, mKeyguardManager, LockTypes.PIN);
         mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pin);
     }
 
@@ -217,7 +222,7 @@
             return;
         }
         mCurrentSaveLockTask = new SaveLockAsyncTask(mInitialLockListener,
-                mInitialLockSetupService, LockTypes.PATTERN);
+                mInitialLockSetupService, mKeyguardManager, LockTypes.PATTERN);
         mCurrentSaveLockTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pattern);
     }
 
@@ -282,29 +287,56 @@
 
         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 @@
 
         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 @@
 
         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 @@
     @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 @@
         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 @@
         }
         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;
+    }
 }