Merge "Remove a window flag."
diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml
index 69b00fe..4096925 100644
--- a/res/layout/face_enroll_introduction.xml
+++ b/res/layout/face_enroll_introduction.xml
@@ -85,12 +85,6 @@
                     android:layout_height="wrap_content"
                     FaceEnrollAccessibilitySwitch:messageText="@string/security_settings_face_enroll_introduction_accessibility_diversity"/>
 
-                <com.android.settings.biometrics.face.FaceEnrollAccessibilityToggle
-                    android:id="@+id/toggle_vision"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    FaceEnrollAccessibilitySwitch:messageText="@string/security_settings_face_enroll_introduction_accessibility_vision"/>
-
             </LinearLayout>
         </FrameLayout>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f77c10d..a4ecd3a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1430,6 +1430,16 @@
     <!-- Title shown on security settings to allow the user to change their lockscreen password [CHAR LIMIT=22]-->
     <string name="unlock_change_lock_password_title">Change unlock password</string>
 
+    <!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and that it requests for a strong PIN or password  [CHAR LIMIT=NONE] -->
+    <string name="unlock_footer_high_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a strong PIN or password.</string>
+    <!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and that it requests for a medium strength PIN or password [CHAR LIMIT=NONE] -->
+    <string name="unlock_footer_medium_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new PIN or password.</string>
+    <!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and it requests for any screen lock [CHAR LIMIT=NONE] -->
+    <string name="unlock_footer_low_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new pattern, PIN or password.</string>
+    <!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock [CHAR LIMIT=NONE] -->
+    <string name="unlock_footer_none_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new screen lock.</string>
+
+
     <!-- Message shown on the lock screen when the user incorrectly enters their lock and it counts towards the max attempts before their data on the device is wiped. [CHAR LIMIT=NONE] -->
     <string name="lock_failed_attempts_before_wipe">Try again. Attempt <xliff:g id="current_attempts">%1$d</xliff:g> of <xliff:g id="total_attempts">%2$d</xliff:g>.</string>
 
@@ -10363,6 +10373,17 @@
     <string name="mobile_data_settings_title">Mobile data</string>
     <!-- Mobile network settings screen, title of Mobile data switch preference [CHAR LIMIT=NONE] -->
     <string name="mobile_data_settings_summary">Access data using mobile network</string>
+    <!-- Mobile network settings screen, title of item showing the name of the default subscription
+     that will be used for calls. This only appears in multi-SIM mode. [CHAR LIMIT=NONE] -->
+    <string name="calls_preference">Calls preference</string>
+    <!-- Mobile network settings screen, title of item showing the name of the default subscription
+     that will be used for SMS messages. This only appears in multi-SIM mode. [CHAR LIMIT=NONE] -->
+    <string name="sms_preference">SMS preference</string>
+    <!-- Mobile network settings screen, a label in a chooser dialog that appears when choosing the
+    default subscription to use for either calls or SMS when in multi-SIM mode. This label means
+    that the user will be asked which mobile network subscription to use every time they place a
+    call or send an SMS, instead of defaulting to one particular subscription. [CHAR LIMIT=40]-->
+    <string name="calls_and_sms_ask_every_time">Ask every time</string>
 
     <!-- Summary of the 'Mobile network' item on the Network & internet page when there is no mobile
          service setup yet (eg no SIM card inserted and no eSIM configured). Tapping it leads to a
diff --git a/res/xml/mobile_network_settings_v2.xml b/res/xml/mobile_network_settings_v2.xml
index 7a19c32..6273ad9 100644
--- a/res/xml/mobile_network_settings_v2.xml
+++ b/res/xml/mobile_network_settings_v2.xml
@@ -17,24 +17,37 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:key="mobile_network_pref_screen"
-    settings:initialExpandedChildrenCount="5">
+    settings:initialExpandedChildrenCount="7">
 
     <com.android.settings.datausage.DataUsageSummaryPreference
         android:key="status_header"
         android:visibility="gone"
         android:selectable="false" />
 
+    <ListPreference
+        android:key="calls_preference"
+        android:title="@string/calls_preference"
+        settings:controller="com.android.settings.network.telephony.CallsDefaultSubscriptionController"
+        settings:allowDividerAbove="true" />
+
+    <ListPreference
+        android:key="sms_preference"
+        android:title="@string/sms_preference"
+        settings:controller="com.android.settings.network.telephony.SmsDefaultSubscriptionController" />
+
     <Preference
         android:key="cdma_lte_data_service_key"
         android:title="@string/cdma_lte_data_service"
-        settings:controller="com.android.settings.network.telephony.DataServiceSetupPreferenceController">
-    </Preference>
+        settings:controller="com.android.settings.network.telephony.DataServiceSetupPreferenceController"
+        settings:allowDividerAbove="true"
+        settings:allowDividerBelow="false" />
 
     <SwitchPreference
         android:key="mobile_data_enable"
         android:title="@string/mobile_data_settings_title"
         android:summary="@string/mobile_data_settings_summary"
-        settings:controller="com.android.settings.network.telephony.MobileDataPreferenceController"/>
+        settings:controller="com.android.settings.network.telephony.MobileDataPreferenceController"
+        settings:allowDividerAbove="true"/>
 
     <com.android.settingslib.RestrictedSwitchPreference
         android:key="button_roaming_key"
diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java
index 5ab543f..0485a0f 100644
--- a/src/com/android/settings/CredentialStorage.java
+++ b/src/com/android/settings/CredentialStorage.java
@@ -55,40 +55,7 @@
 import sun.security.x509.AlgorithmId;
 
 /**
- * CredentialStorage handles KeyStore reset, unlock, and install.
- *
- * CredentialStorage has a pretty convoluted state machine to migrate
- * from the old style separate keystore password to a new key guard
- * based password, as well as to deal with setting up the key guard if
- * necessary.
- *
- * KeyStore: UNINITALIZED
- * KeyGuard: OFF
- * Action:   set up key guard
- * Notes:    factory state
- *
- * KeyStore: UNINITALIZED
- * KeyGuard: ON
- * Action:   confirm key guard
- * Notes:    user had key guard but no keystore and upgraded from pre-ICS
- * OR user had key guard and pre-ICS keystore password which was then reset
- *
- * KeyStore: LOCKED
- * KeyGuard: OFF/ON
- * Action:   confirm key guard
- * Notes:    request normal unlock to unlock the keystore.
- * if unlock, ensure key guard before install.
- * if reset, treat as UNINITALIZED/OFF
- *
- * KeyStore: UNLOCKED
- * KeyGuard: OFF
- * Action:   set up key guard
- * Notes:    ensure key guard, then proceed
- *
- * KeyStore: UNLOCKED
- * keyguard: ON
- * Action:   normal unlock/install
- * Notes:    this is the common case
+ * CredentialStorage handles resetting and installing keys into KeyStore.
  */
 public final class CredentialStorage extends FragmentActivity {
 
@@ -102,8 +69,7 @@
     // lower than this, keystore should not be activated.
     public static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 
-    private static final int CONFIRM_KEY_GUARD_REQUEST = 1;
-    private static final int CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST = 2;
+    private static final int CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST = 1;
 
     private final KeyStore mKeyStore = KeyStore.getInstance();
     private LockPatternUtils mUtils;
@@ -133,75 +99,26 @@
                 if (ACTION_INSTALL.equals(action) && checkCallerIsCertInstallerOrSelfInProfile()) {
                     mInstallBundle = intent.getExtras();
                 }
-                // ACTION_UNLOCK also handled here in addition to ACTION_INSTALL
-                handleUnlockOrInstall();
+                handleInstall();
             }
         } else {
-            // Users can set a screen lock if there is none even if they can't modify the
-            // credentials store.
-            if (ACTION_UNLOCK.equals(action) && mKeyStore.state() == KeyStore.State.UNINITIALIZED) {
-                ensureKeyGuard();
-            } else {
-                finish();
-            }
+            finish();
         }
     }
 
     /**
-     * Based on the current state of the KeyStore and key guard, try to
-     * make progress on unlocking or installing to the keystore.
+     * Install credentials from mInstallBundle into Keystore.
      */
-    private void handleUnlockOrInstall() {
+    private void handleInstall() {
         // something already decided we are done, do not proceed
         if (isFinishing()) {
             return;
         }
-        switch (mKeyStore.state()) {
-            case UNINITIALIZED: {
-                ensureKeyGuard();
-                return;
-            }
-            case LOCKED: {
-                // Force key guard confirmation
-                confirmKeyGuard(CONFIRM_KEY_GUARD_REQUEST);
-                return;
-            }
-            case UNLOCKED: {
-                if (!mUtils.isSecure(UserHandle.myUserId())) {
-                    final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog();
-                    dialog.show(getSupportFragmentManager(), ConfigureKeyGuardDialog.TAG);
-                    return;
-                }
-                if (installIfAvailable()) {
-                    finish();
-                }
-                return;
-            }
+        if (installIfAvailable()) {
+            finish();
         }
     }
 
-    /**
-     * Make sure the user enters the key guard to set or change the
-     * keystore password. This can be used in UNINITIALIZED to set the
-     * keystore password or UNLOCKED to change the password (as is the
-     * case after unlocking with an old-style password).
-     */
-    private void ensureKeyGuard() {
-        if (!mUtils.isSecure(UserHandle.myUserId())) {
-            // key guard not setup, doing so will initialize keystore
-            final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog();
-            dialog.show(getSupportFragmentManager(), ConfigureKeyGuardDialog.TAG);
-            // will return to onResume after Activity
-            return;
-        }
-        // force key guard confirmation
-        if (confirmKeyGuard(CONFIRM_KEY_GUARD_REQUEST)) {
-            // will return password value via onActivityResult
-            return;
-        }
-        finish();
-    }
-
     private boolean isHardwareBackedKey(byte[] keyData) {
         try {
             final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
@@ -254,15 +171,7 @@
             final String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
             final byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
 
-            int flags = KeyStore.FLAG_ENCRYPTED;
-            if (uid == Process.WIFI_UID && isHardwareBackedKey(value)) {
-                // Hardware backed keystore is secure enough to allow for WIFI stack
-                // to enable access to secure networks without user intervention
-                Log.d(TAG, "Saving private key with FLAG_NONE for WIFI_UID");
-                flags = KeyStore.FLAG_NONE;
-            }
-
-            if (!mKeyStore.importKey(key, value, uid, flags)) {
+            if (!mKeyStore.importKey(key, value, uid, KeyStore.FLAG_NONE)) {
                 Log.e(TAG, "Failed to install " + key + " as uid " + uid);
                 return true;
             }
@@ -475,20 +384,7 @@
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-        // Receive key guard password initiated by confirmKeyGuard.
-        if (requestCode == CONFIRM_KEY_GUARD_REQUEST) {
-            if (resultCode == Activity.RESULT_OK) {
-                final String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
-                if (!TextUtils.isEmpty(password)) {
-                    // success
-                    mKeyStore.unlock(password);
-                    // return to onResume
-                    return;
-                }
-            }
-            // failed confirmation, bail
-            finish();
-        } else if (requestCode == CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST) {
+        if (requestCode == CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST) {
             if (resultCode == Activity.RESULT_OK) {
                 new ResetKeyStoreAndKeyChain().execute();
                 return;
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index fc4f6ce..71bd02f 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -43,7 +43,6 @@
     private static final String TAG = "FaceIntro";
 
     private FaceManager mFaceManager;
-    private FaceEnrollAccessibilityToggle mSwitchVision;
     private FaceEnrollAccessibilityToggle mSwitchDiversity;
 
     @Override
@@ -57,7 +56,6 @@
             accessibilityLayout.setVisibility(View.VISIBLE);
         });
 
-        mSwitchVision = findViewById(R.id.toggle_vision);
         mSwitchDiversity = findViewById(R.id.toggle_diversity);
 
         mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
@@ -167,7 +165,6 @@
         } else {
             intent.setClass(this, FaceEnrollEnrolling.class);
         }
-        intent.putExtra(EXTRA_KEY_REQUIRE_VISION, mSwitchVision.isChecked());
         intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, mSwitchDiversity.isChecked());
         return intent;
     }
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index c3d49e9..6ff4309 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -109,12 +109,14 @@
         mCachedDevice = getCachedDevice(mDeviceAddress);
         super.onAttach(context);
 
-        if (FeatureFlagUtils.isEnabled(context, FeatureFlags.SLICE_INJECTION)) {
-            final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(context)
-                    .getBluetoothFeatureProvider(context);
-            use(BlockingSlicePrefController.class).setSliceUri(
-                    featureProvider.getBluetoothDeviceSettingsUri(mDeviceAddress));
-        }
+        final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
+                context).getBluetoothFeatureProvider(context);
+        final boolean injectionEnabled = FeatureFlagUtils.isEnabled(context,
+                FeatureFlags.SLICE_INJECTION);
+
+        use(BlockingSlicePrefController.class).setSliceUri(injectionEnabled
+                ? featureProvider.getBluetoothDeviceSettingsUri(mDeviceAddress)
+                : null);
     }
 
     @Override
diff --git a/src/com/android/settings/display/NightDisplayActivationPreferenceController.java b/src/com/android/settings/display/NightDisplayActivationPreferenceController.java
index 35cb5ed..17c16e7 100644
--- a/src/com/android/settings/display/NightDisplayActivationPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayActivationPreferenceController.java
@@ -67,8 +67,7 @@
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
 
-        final LayoutPreference preference = (LayoutPreference) screen.findPreference(
-                getPreferenceKey());
+        final LayoutPreference preference = screen.findPreference(getPreferenceKey());
         mTurnOnButton = preference.findViewById(R.id.night_display_turn_on_button);
         mTurnOnButton.setOnClickListener(mListener);
         mTurnOffButton = preference.findViewById(R.id.night_display_turn_off_button);
@@ -106,14 +105,14 @@
         final int autoMode = mController.getAutoMode();
 
         String buttonText;
-        if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM) {
+        if (autoMode == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME) {
             buttonText = mContext.getString(isActivated
                             ? R.string.night_display_activation_off_custom
                             : R.string.night_display_activation_on_custom,
                     mTimeFormatter.getFormattedTimeString(isActivated
                             ? mController.getCustomStartTime()
                             : mController.getCustomEndTime()));
-        } else if (autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
+        } else if (autoMode == ColorDisplayManager.AUTO_MODE_TWILIGHT) {
             buttonText = mContext.getString(isActivated
                     ? R.string.night_display_activation_off_twilight
                     : R.string.night_display_activation_on_twilight);
diff --git a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
index 1710f51..33e3e6f 100644
--- a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
@@ -23,7 +23,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.internal.app.ColorDisplayController;
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 
@@ -31,11 +30,11 @@
         implements Preference.OnPreferenceChangeListener {
 
     private DropDownPreference mPreference;
-    private ColorDisplayController mController;
+    private ColorDisplayManager mManager;
 
     public NightDisplayAutoModePreferenceController(Context context, String key) {
         super(context, key);
-        mController = new ColorDisplayController(context);
+        mManager = context.getSystemService(ColorDisplayManager.class);
     }
 
     @Override
@@ -48,7 +47,7 @@
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
 
-        mPreference = (DropDownPreference) screen.findPreference(getPreferenceKey());
+        mPreference = screen.findPreference(getPreferenceKey());
 
         mPreference.setEntries(new CharSequence[]{
                 mContext.getString(R.string.night_display_auto_mode_never),
@@ -56,19 +55,19 @@
                 mContext.getString(R.string.night_display_auto_mode_twilight)
         });
         mPreference.setEntryValues(new CharSequence[]{
-                String.valueOf(ColorDisplayController.AUTO_MODE_DISABLED),
-                String.valueOf(ColorDisplayController.AUTO_MODE_CUSTOM),
-                String.valueOf(ColorDisplayController.AUTO_MODE_TWILIGHT)
+                String.valueOf(ColorDisplayManager.AUTO_MODE_DISABLED),
+                String.valueOf(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME),
+                String.valueOf(ColorDisplayManager.AUTO_MODE_TWILIGHT)
         });
     }
 
     @Override
     public final void updateState(Preference preference) {
-        mPreference.setValue(String.valueOf(mController.getAutoMode()));
+        mPreference.setValue(String.valueOf(mManager.getNightDisplayAutoMode()));
     }
 
     @Override
     public final boolean onPreferenceChange(Preference preference, Object newValue) {
-        return mController.setAutoMode(Integer.parseInt((String) newValue));
+        return mManager.setNightDisplayAutoMode(Integer.parseInt((String) newValue));
     }
 }
diff --git a/src/com/android/settings/display/NightDisplayCustomEndTimePreferenceController.java b/src/com/android/settings/display/NightDisplayCustomEndTimePreferenceController.java
index 2fa0ef5..b12c18a 100644
--- a/src/com/android/settings/display/NightDisplayCustomEndTimePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayCustomEndTimePreferenceController.java
@@ -18,9 +18,7 @@
 
 import android.content.Context;
 import android.hardware.display.ColorDisplayManager;
-
 import androidx.preference.Preference;
-
 import com.android.internal.app.ColorDisplayController;
 import com.android.settings.core.BasePreferenceController;
 
@@ -44,7 +42,8 @@
 
     @Override
     public final void updateState(Preference preference) {
-        preference.setVisible(mController.getAutoMode() == ColorDisplayController.AUTO_MODE_CUSTOM);
+        preference
+                .setVisible(mController.getAutoMode() == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
         preference.setSummary(mTimeFormatter.getFormattedTimeString(
                 mController.getCustomEndTime()));
     }
diff --git a/src/com/android/settings/display/NightDisplayCustomStartTimePreferenceController.java b/src/com/android/settings/display/NightDisplayCustomStartTimePreferenceController.java
index cf740fd..10fb3a1 100644
--- a/src/com/android/settings/display/NightDisplayCustomStartTimePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayCustomStartTimePreferenceController.java
@@ -18,9 +18,7 @@
 
 import android.content.Context;
 import android.hardware.display.ColorDisplayManager;
-
 import androidx.preference.Preference;
-
 import com.android.internal.app.ColorDisplayController;
 import com.android.settings.core.BasePreferenceController;
 
@@ -44,7 +42,8 @@
 
     @Override
     public final void updateState(Preference preference) {
-        preference.setVisible(mController.getAutoMode() == ColorDisplayController.AUTO_MODE_CUSTOM);
+        preference
+                .setVisible(mController.getAutoMode() == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
         preference.setSummary(mTimeFormatter.getFormattedTimeString(
                 mController.getCustomStartTime()));
     }
diff --git a/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java b/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
index 6adaf23..7487873 100644
--- a/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
@@ -22,6 +22,7 @@
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.app.ColorDisplayController;
 import com.android.settings.core.SliderPreferenceController;
@@ -54,8 +55,7 @@
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
-        final SeekBarPreference preference = (SeekBarPreference) screen.findPreference(
-                getPreferenceKey());
+        final SeekBarPreference preference = screen.findPreference(getPreferenceKey());
         preference.setContinuousUpdates(true);
         preference.setMax(getMaxSteps());
     }
diff --git a/src/com/android/settings/display/NightDisplayPreferenceController.java b/src/com/android/settings/display/NightDisplayPreferenceController.java
index 162a648..ab0250d 100644
--- a/src/com/android/settings/display/NightDisplayPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayPreferenceController.java
@@ -38,7 +38,7 @@
             return true;
         }
         final ColorDisplayController controller = new ColorDisplayController(context);
-        return controller.getAutoMode() != ColorDisplayController.AUTO_MODE_DISABLED;
+        return controller.getAutoMode() != ColorDisplayManager.AUTO_MODE_DISABLED;
     }
 
     @Override
diff --git a/src/com/android/settings/display/NightDisplayTimeFormatter.java b/src/com/android/settings/display/NightDisplayTimeFormatter.java
index 48a1994..1b82e0a 100644
--- a/src/com/android/settings/display/NightDisplayTimeFormatter.java
+++ b/src/com/android/settings/display/NightDisplayTimeFormatter.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 
+import android.hardware.display.ColorDisplayManager;
 import com.android.internal.app.ColorDisplayController;
 import com.android.settings.R;
 
@@ -54,7 +55,7 @@
     private String getAutoModeSummary(Context context, ColorDisplayController controller) {
         final boolean isActivated = controller.isActivated();
         final int autoMode = controller.getAutoMode();
-        if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM) {
+        if (autoMode == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME) {
             if (isActivated) {
                 return context.getString(R.string.night_display_summary_on_auto_mode_custom,
                         getFormattedTimeString(controller.getCustomEndTime()));
@@ -62,7 +63,7 @@
                 return context.getString(R.string.night_display_summary_off_auto_mode_custom,
                         getFormattedTimeString(controller.getCustomStartTime()));
             }
-        } else if (autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
+        } else if (autoMode == ColorDisplayManager.AUTO_MODE_TWILIGHT) {
             return context.getString(isActivated
                     ? R.string.night_display_summary_on_auto_mode_twilight
                     : R.string.night_display_summary_off_auto_mode_twilight);
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java
index ff26888..1602f56 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java
@@ -30,16 +30,11 @@
 
     private static final String TAG = "BluetoothUpdateWorker";
 
-    private final Context mContext;
-    private final Uri mUri;
     private final LocalBluetoothManager mLocalBluetoothManager;
 
     public BluetoothUpdateWorker(Context context, Uri uri) {
         super(context, uri);
-
-        mContext = context;
-        mUri = uri;
-        mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
+        mLocalBluetoothManager = Utils.getLocalBtManager(context);
     }
 
     @Override
@@ -89,8 +84,4 @@
             int bluetoothProfile) {
         notifySliceChange();
     }
-
-    private void notifySliceChange() {
-        mContext.getContentResolver().notifyChange(mUri, null);
-    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
index 2d84e21..3adc489 100644
--- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
+++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
@@ -13,6 +13,8 @@
  */
 package com.android.settings.location;
 
+import static java.util.concurrent.TimeUnit.DAYS;
+
 import android.Manifest;
 import android.content.Context;
 import android.content.Intent;
@@ -74,6 +76,7 @@
                     final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
                     intent.putExtra(Intent.EXTRA_PERMISSION_NAME,
                             Manifest.permission.ACCESS_FINE_LOCATION);
+                    intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
                     mContext.startActivity(intent);
                 });
     }
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index fbc6edd..237e08a 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -30,7 +30,7 @@
     private static List<SubscriptionInfo> sResultsForTesting;
 
     @VisibleForTesting
-    static void setAvailableSubscriptionsForTesting(List<SubscriptionInfo> results) {
+    public static void setAvailableSubscriptionsForTesting(List<SubscriptionInfo> results) {
         sResultsForTesting = results;
     }
 
diff --git a/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java b/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java
new file mode 100644
index 0000000..008a3e4
--- /dev/null
+++ b/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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.settings.network.telephony;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+public class CallsDefaultSubscriptionController extends DefaultSubscriptionController {
+
+    public CallsDefaultSubscriptionController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    protected SubscriptionInfo getDefaultSubscriptionInfo() {
+        return mManager.getDefaultVoiceSubscriptionInfo();
+    }
+
+    @Override
+    protected int getDefaultSubscriptionId() {
+        return SubscriptionManager.getDefaultVoiceSubscriptionId();
+    }
+
+    @Override
+    protected void setDefaultSubscription(int subscriptionId) {
+        mManager.setDefaultVoiceSubId(subscriptionId);
+    }
+}
diff --git a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
new file mode 100644
index 0000000..bca6750
--- /dev/null
+++ b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2019 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.settings.network.telephony;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.SubscriptionsChangeListener;
+
+import java.util.List;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+/**
+ * This implements common controller functionality for a Preference letting the user see/change
+ * what mobile network subscription is used by default for some service controlled by the
+ * SubscriptionManager. This can be used for services such as Calls or SMS.
+ */
+public abstract class DefaultSubscriptionController extends BasePreferenceController implements
+        LifecycleObserver, Preference.OnPreferenceChangeListener,
+        SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+    private static final String TAG = "DefaultSubController";
+
+    protected SubscriptionsChangeListener mChangeListener;
+    protected ListPreference mPreference;
+    protected SubscriptionManager mManager;
+
+    public DefaultSubscriptionController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+        mManager = context.getSystemService(SubscriptionManager.class);
+        mChangeListener = new SubscriptionsChangeListener(context, this);
+    }
+
+    public void init(Lifecycle lifecycle) {
+        lifecycle.addObserver(this);
+    }
+
+    /** @return SubscriptionInfo for the default subscription for the service, or null if there
+     * isn't one. */
+    protected abstract SubscriptionInfo getDefaultSubscriptionInfo();
+
+    /** @return the id of the default subscription for the service, or
+     * SubscriptionManager.INVALID_SUBSCRIPTION_ID if there isn't one. */
+    protected abstract int getDefaultSubscriptionId();
+
+    /** Called to change the default subscription for the service. */
+    protected abstract void setDefaultSubscription(int subscriptionId);
+
+    @Override
+    public int getAvailabilityStatus() {
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+        if (subs.size() > 1) {
+            return AVAILABLE;
+        } else {
+            return CONDITIONALLY_UNAVAILABLE;
+        }
+    }
+
+    @OnLifecycleEvent(ON_RESUME)
+    public void onResume() {
+        mChangeListener.start();
+        updateEntries();
+    }
+
+    @OnLifecycleEvent(ON_PAUSE)
+    public void onPause() {
+        mChangeListener.stop();
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
+        updateEntries();
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        final SubscriptionInfo info = getDefaultSubscriptionInfo();
+        if (info != null) {
+            return info.getDisplayName();
+        } else {
+            return mContext.getString(R.string.calls_and_sms_ask_every_time);
+        }
+    }
+
+    private void updateEntries() {
+        if (mPreference == null) {
+            return;
+        }
+        if (!isAvailable()) {
+            mPreference.setVisible(false);
+            return;
+        }
+        mPreference.setVisible(true);
+
+        final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+
+        // We'll have one entry for each available subscription, plus one for a "ask me every
+        // time" entry at the end.
+        final CharSequence[] displayNames = new CharSequence[subs.size() + 1];
+        final CharSequence[] subscriptionIds = new CharSequence[subs.size() + 1];
+
+        final int serviceDefaultSubId = getDefaultSubscriptionId();
+        boolean subIsAvailable = false;
+
+        int i = 0;
+        for (; i < subs.size(); i++) {
+            displayNames[i] = subs.get(i).getDisplayName();
+            final int subId = subs.get(i).getSubscriptionId();
+            subscriptionIds[i] = Integer.toString(subId);
+            if (subId == serviceDefaultSubId) {
+                subIsAvailable = true;
+            }
+        }
+        // Add the extra "Ask every time" value at the end.
+        displayNames[i] = mContext.getString(R.string.calls_and_sms_ask_every_time);
+        subscriptionIds[i] = Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+        mPreference.setEntries(displayNames);
+        mPreference.setEntryValues(subscriptionIds);
+
+        if (subIsAvailable) {
+            mPreference.setValue(Integer.toString(serviceDefaultSubId));
+        } else {
+            mPreference.setValue(Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final int subscriptionId = Integer.parseInt((String) newValue);
+        setDefaultSubscription(subscriptionId);
+        refreshSummary(mPreference);
+        return true;
+    }
+
+    @Override
+    public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+    }
+
+    @Override
+    public void onSubscriptionsChanged() {
+        if (mPreference != null) {
+            updateEntries();
+            refreshSummary(mPreference);
+        }
+    }
+}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 9665c09..5201586 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -126,6 +126,10 @@
     public void onAttach(Context context) {
         super.onAttach(context);
 
+        if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2)) {
+          use(CallsDefaultSubscriptionController.class).init(getLifecycle());
+          use(SmsDefaultSubscriptionController.class).init(getLifecycle());
+        }
         use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
         use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
         use(ApnPreferenceController.class).init(mSubId);
diff --git a/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java b/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java
new file mode 100644
index 0000000..b999219
--- /dev/null
+++ b/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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.settings.network.telephony;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+public class SmsDefaultSubscriptionController extends DefaultSubscriptionController {
+
+    public SmsDefaultSubscriptionController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    protected SubscriptionInfo getDefaultSubscriptionInfo() {
+        return mManager.getDefaultSmsSubscriptionInfo();
+    }
+
+    @Override
+    protected int getDefaultSubscriptionId() {
+        return SubscriptionManager.getDefaultSmsSubscriptionId();
+    }
+
+    @Override
+    protected void setDefaultSubscription(int subscriptionId) {
+        mManager.setDefaultSmsSubId(subscriptionId);
+    }
+}
diff --git a/src/com/android/settings/password/BiometricFragment.java b/src/com/android/settings/password/BiometricFragment.java
index 13ec543..171b61e 100644
--- a/src/com/android/settings/password/BiometricFragment.java
+++ b/src/com/android/settings/password/BiometricFragment.java
@@ -43,6 +43,7 @@
     private static final String KEY_SUBTITLE = "subtitle";
     private static final String KEY_DESCRIPTION = "description";
     private static final String KEY_NEGATIVE_TEXT = "negative_text";
+    private static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation";
 
     // Re-set by the application. Should be done upon orientation changes, etc
     private Executor mClientExecutor;
@@ -127,6 +128,7 @@
             .setDescription(mPromptInfo.getDescription())
             .setNegativeButton(mPromptInfo.getNegativeButtonText(), mClientExecutor,
                     mNegativeButtonListener)
+            .setRequireConfirmation(mPromptInfo.getRequireConfirmation())
             .build();
         mCancellationSignal = new CancellationSignal();
 
@@ -171,6 +173,10 @@
             return mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
         }
 
+        public boolean getRequireConfirmation() {
+            return mBundle.getBoolean(KEY_REQUIRE_CONFIRMATION);
+        }
+
         public static class Builder {
             private final Bundle mBundle = new Bundle();
 
@@ -194,6 +200,11 @@
                 return this;
             }
 
+            public Builder setRequireConfirmation(boolean requireConfirmation) {
+                mBundle.putBoolean(KEY_REQUIRE_CONFIRMATION, requireConfirmation);
+                return this;
+            }
+
             public PromptInfo build() {
                 return new PromptInfo(mBundle);
             }
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index ca96344..cae7d33 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -18,13 +18,20 @@
 
 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
 
 import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.Activity;
 import android.app.Dialog;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.Intent;
@@ -66,6 +73,8 @@
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.RestrictedPreference;
+import com.android.settingslib.widget.FooterPreference;
+import com.android.settingslib.widget.FooterPreferenceMixinCompat;
 
 import java.util.List;
 
@@ -152,6 +161,14 @@
         private UserManager mUserManager;
         private ChooseLockGenericController mController;
 
+        /**
+         * From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_REQUESTED_MIN_COMPLEXITY}.
+         */
+        @PasswordComplexity private int mRequestedMinComplexity;
+
+        /** From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_CALLER_APP_NAME}. */
+        private String mCallerAppName = null;
+
         protected boolean mForFingerprint = false;
         protected boolean mForFace = false;
 
@@ -195,6 +212,10 @@
                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
             mForFace = getActivity().getIntent().getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
+            mRequestedMinComplexity = getActivity().getIntent()
+                    .getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
+            mCallerAppName =
+                    getActivity().getIntent().getStringExtra(EXTRA_KEY_CALLER_APP_NAME);
             mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
             mUserManager = UserManager.get(getActivity());
@@ -217,7 +238,8 @@
                     UserManager.get(getActivity()),
                     getArguments(),
                     getActivity().getIntent().getExtras()).getIdentifier();
-            mController = new ChooseLockGenericController(getContext(), mUserId);
+            mController =
+                    new ChooseLockGenericController(getContext(), mUserId, mRequestedMinComplexity);
             if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
                     && UserManager.get(getActivity()).isManagedProfile(mUserId)
                     && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
@@ -291,6 +313,9 @@
                 // Forward the target user id to  ChooseLockGeneric.
                 chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
                 chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
+                chooseLockGenericIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
+                        mRequestedMinComplexity);
+                chooseLockGenericIntent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
                 if (mUserPassword != null) {
                     chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
                             mUserPassword);
@@ -461,6 +486,13 @@
         protected void addPreferences() {
             addPreferencesFromResource(R.xml.security_settings_picker);
 
+            if (!TextUtils.isEmpty(mCallerAppName)) {
+                FooterPreferenceMixinCompat footerMixin =
+                        new FooterPreferenceMixinCompat(this, getSettingsLifecycle());
+                FooterPreference footer = footerMixin.createFooterPreference();
+                footer.setTitle(getFooterString());
+            }
+
             // Used for testing purposes
             findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
             findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
@@ -469,6 +501,27 @@
             findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
         }
 
+        private String getFooterString() {
+            @StringRes int stringId;
+            switch (mRequestedMinComplexity) {
+                case PASSWORD_COMPLEXITY_HIGH:
+                    stringId = R.string.unlock_footer_high_complexity_requested;
+                    break;
+                case PASSWORD_COMPLEXITY_MEDIUM:
+                    stringId = R.string.unlock_footer_medium_complexity_requested;
+                    break;
+                case PASSWORD_COMPLEXITY_LOW:
+                    stringId = R.string.unlock_footer_low_complexity_requested;
+                    break;
+                case PASSWORD_COMPLEXITY_NONE:
+                default:
+                    stringId = R.string.unlock_footer_none_complexity_requested;
+                    break;
+            }
+
+            return getResources().getString(stringId, mCallerAppName);
+        }
+
         private void updatePreferenceText() {
             if (mForFingerprint) {
                 setPreferenceTitle(ScreenLockType.PATTERN,
@@ -624,6 +677,7 @@
             ChooseLockPassword.IntentBuilder builder =
                     new ChooseLockPassword.IntentBuilder(getContext())
                             .setPasswordQuality(quality)
+                            .setRequestedMinComplexity(mRequestedMinComplexity)
                             .setForFingerprint(mForFingerprint)
                             .setForFace(mForFace)
                             .setUserId(mUserId);
diff --git a/src/com/android/settings/password/ChooseLockGenericController.java b/src/com/android/settings/password/ChooseLockGenericController.java
index eb7ff4e..91ca957 100644
--- a/src/com/android/settings/password/ChooseLockGenericController.java
+++ b/src/com/android/settings/password/ChooseLockGenericController.java
@@ -16,7 +16,11 @@
 
 package com.android.settings.password;
 
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
+import android.app.admin.PasswordMetrics;
 import android.content.Context;
 import android.os.UserHandle;
 
@@ -36,6 +40,7 @@
 
     private final Context mContext;
     private final int mUserId;
+    @PasswordComplexity private final int mRequestedMinComplexity;
     private ManagedLockPasswordProvider mManagedPasswordProvider;
     private DevicePolicyManager mDpm;
 
@@ -43,6 +48,19 @@
         this(
                 context,
                 userId,
+                PASSWORD_COMPLEXITY_NONE);
+    }
+
+    /**
+     * @param requestedMinComplexity specifies the min password complexity to be taken into account
+     *                               when determining the available screen lock types
+     */
+    public ChooseLockGenericController(Context context, int userId,
+            @PasswordComplexity int requestedMinComplexity) {
+        this(
+                context,
+                userId,
+                requestedMinComplexity,
                 context.getSystemService(DevicePolicyManager.class),
                 ManagedLockPasswordProvider.get(context, userId));
     }
@@ -51,21 +69,26 @@
     ChooseLockGenericController(
             Context context,
             int userId,
+            @PasswordComplexity int requestedMinComplexity,
             DevicePolicyManager dpm,
             ManagedLockPasswordProvider managedLockPasswordProvider) {
         mContext = context;
         mUserId = userId;
+        mRequestedMinComplexity = requestedMinComplexity;
         mManagedPasswordProvider = managedLockPasswordProvider;
         mDpm = dpm;
     }
 
     /**
-     * @return The higher quality of either the specified {@code quality} or the quality required
-     *         by {@link DevicePolicyManager#getPasswordQuality}.
+     * Returns the highest quality among the specified {@code quality}, the quality required by
+     * {@link DevicePolicyManager#getPasswordQuality}, and the quality required by min password
+     * complexity.
      */
     public int upgradeQuality(int quality) {
-        // Compare min allowed password quality
-        return Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
+        // Compare specified quality and dpm quality
+        int dpmUpgradedQuality = Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
+        return Math.max(dpmUpgradedQuality,
+                PasswordMetrics.complexityLevelToMinQuality(mRequestedMinComplexity));
     }
 
     /**
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 0ae664c..129f9ac 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -16,14 +16,18 @@
 
 package com.android.settings.password;
 
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
 
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.app.admin.PasswordMetrics;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
@@ -56,6 +60,7 @@
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
 import com.android.internal.widget.TextViewInputDisabler;
@@ -133,6 +138,11 @@
             return this;
         }
 
+        public IntentBuilder setRequestedMinComplexity(@PasswordComplexity int level) {
+            mIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, level);
+            return this;
+        }
+
         public Intent build() {
             return mIntent;
         }
@@ -190,12 +200,10 @@
         private int mPasswordMinNumeric = 0;
         private int mPasswordMinNonLetter = 0;
         private int mPasswordMinLengthToFulfillAllPolicies = 0;
+        private boolean mPasswordNumSequenceAllowed = true;
+        @PasswordComplexity private int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
         protected int mUserId;
         private byte[] mPasswordHistoryHashFactor;
-        /**
-         * Password requirements that we need to verify.
-         */
-        private int[] mPasswordRequirements;
 
         private LockPatternUtils mLockPatternUtils;
         private SaveAndFinishWorker mSaveAndFinishWorker;
@@ -372,7 +380,13 @@
             mForFingerprint = intent.getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
             mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
-            processPasswordRequirements(intent);
+            mRequestedMinComplexity = intent.getIntExtra(
+                    EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
+            mRequestedQuality = Math.max(
+                    intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality),
+                    mLockPatternUtils.getRequestedPasswordQuality(mUserId));
+
+            loadDpmPasswordRequirements();
             mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
 
             if (intent.getBooleanExtra(
@@ -504,31 +518,6 @@
         }
 
         private void setupPasswordRequirementsView(View view) {
-            final List<Integer> passwordRequirements = new ArrayList<>();
-            if (mPasswordMinUpperCase > 0) {
-                passwordRequirements.add(MIN_UPPER_LETTERS_IN_PASSWORD);
-            }
-            if (mPasswordMinLowerCase > 0) {
-                passwordRequirements.add(MIN_LOWER_LETTERS_IN_PASSWORD);
-            }
-            if (mPasswordMinLetters > 0) {
-                if (mPasswordMinLetters > mPasswordMinUpperCase + mPasswordMinLowerCase) {
-                    passwordRequirements.add(MIN_LETTER_IN_PASSWORD);
-                }
-            }
-            if (mPasswordMinNumeric > 0) {
-                passwordRequirements.add(MIN_NUMBER_IN_PASSWORD);
-            }
-            if (mPasswordMinSymbols > 0) {
-                passwordRequirements.add(MIN_SYMBOLS_IN_PASSWORD);
-            }
-            if (mPasswordMinNonLetter > 0) {
-                if (mPasswordMinNonLetter > mPasswordMinNumeric + mPasswordMinSymbols) {
-                    passwordRequirements.add(MIN_NON_LETTER_IN_PASSWORD);
-                }
-            }
-            // Convert list to array.
-            mPasswordRequirements = passwordRequirements.stream().mapToInt(i -> i).toArray();
             mPasswordRestrictionView = view.findViewById(R.id.password_requirements_view);
             mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
             mPasswordRequirementAdapter = new PasswordRequirementAdapter();
@@ -603,13 +592,12 @@
 
         /**
          * Read the requirements from {@link DevicePolicyManager} and intent and aggregate them.
-         *
-         * @param intent the incoming intent
          */
-        private void processPasswordRequirements(Intent intent) {
+        private void loadDpmPasswordRequirements() {
             final int dpmPasswordQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
-            mRequestedQuality = Math.max(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY,
-                    mRequestedQuality), dpmPasswordQuality);
+            if (dpmPasswordQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
+                mPasswordNumSequenceAllowed = false;
+            }
             mPasswordMinLength = Math.max(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
                     mLockPatternUtils.getRequestedMinimumPasswordLength(mUserId));
             mPasswordMaxLength = mLockPatternUtils.getMaximumPasswordLength(mRequestedQuality);
@@ -620,7 +608,7 @@
             mPasswordMinSymbols = mLockPatternUtils.getRequestedPasswordMinimumSymbols(mUserId);
             mPasswordMinNonLetter = mLockPatternUtils.getRequestedPasswordMinimumNonLetter(mUserId);
 
-            // Modify the value based on dpm policy.
+            // Modify the value based on dpm policy
             switch (dpmPasswordQuality) {
                 case PASSWORD_QUALITY_ALPHABETIC:
                     if (mPasswordMinLetters == 0) {
@@ -646,19 +634,88 @@
                     mPasswordMinSymbols = 0;
                     mPasswordMinNonLetter = 0;
             }
+
             mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
         }
 
         /**
+         * Merges the dpm requirements and the min complexity requirements.
+         *
+         * <p>Since there are more than one set of metrics to meet the min complexity requirement,
+         * and we are not hard-coding any one of them to be the requirements the user must fulfil,
+         * we are taking what the user has already entered into account when compiling the list of
+         * requirements from min complexity. Then we merge this list with the DPM requirements, and
+         * present the merged set as validation results to the user on the UI.
+         *
+         * <p>For example, suppose min complexity requires either ALPHABETIC(8+), or
+         * ALPHANUMERIC(6+). If the user has entered "a", the length requirement displayed on the UI
+         * would be 8. Then the user appends "1" to make it "a1". We now know the user is entering
+         * an alphanumeric password so we would update the min complexity required min length to 6.
+         * This might result in a little confusion for the user but the UI does not support showing
+         * multiple sets of requirements / validation results as options to users, this is the best
+         * we can do now.
+         */
+        private void mergeMinComplexityAndDpmRequirements(int userEnteredPasswordQuality) {
+            if (mRequestedMinComplexity == PASSWORD_COMPLEXITY_NONE) {
+                // dpm requirements are dominant if min complexity is none
+                return;
+            }
+
+            // reset dpm requirements
+            loadDpmPasswordRequirements();
+
+            PasswordMetrics minMetrics = PasswordMetrics.getMinimumMetrics(
+                    mRequestedMinComplexity, userEnteredPasswordQuality, mRequestedQuality,
+                    requiresNumeric(), requiresLettersOrSymbols());
+            mPasswordNumSequenceAllowed = mPasswordNumSequenceAllowed
+                    && minMetrics.quality != PASSWORD_QUALITY_NUMERIC_COMPLEX;
+            mPasswordMinLength = Math.max(mPasswordMinLength, minMetrics.length);
+            mPasswordMinLetters = Math.max(mPasswordMinLetters, minMetrics.letters);
+            mPasswordMinUpperCase = Math.max(mPasswordMinUpperCase, minMetrics.upperCase);
+            mPasswordMinLowerCase = Math.max(mPasswordMinLowerCase, minMetrics.lowerCase);
+            mPasswordMinNumeric = Math.max(mPasswordMinNumeric, minMetrics.numeric);
+            mPasswordMinSymbols = Math.max(mPasswordMinSymbols, minMetrics.symbols);
+            mPasswordMinNonLetter = Math.max(mPasswordMinNonLetter, minMetrics.nonLetter);
+
+            if (minMetrics.quality == PASSWORD_QUALITY_ALPHABETIC) {
+                if (!requiresLettersOrSymbols()) {
+                    mPasswordMinLetters = 1;
+                }
+            }
+            if (minMetrics.quality == PASSWORD_QUALITY_ALPHANUMERIC) {
+                if (!requiresLettersOrSymbols()) {
+                    mPasswordMinLetters = 1;
+                }
+                if (!requiresNumeric()) {
+                    mPasswordMinNumeric = 1;
+                }
+            }
+
+            mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
+        }
+
+        private boolean requiresLettersOrSymbols() {
+            // This is the condition for the password to be considered ALPHABETIC according to
+            // PasswordMetrics.computeForPassword()
+            return mPasswordMinLetters + mPasswordMinUpperCase
+                    + mPasswordMinLowerCase + mPasswordMinSymbols + mPasswordMinNonLetter > 0;
+        }
+
+        private boolean requiresNumeric() {
+            return mPasswordMinNumeric > 0;
+        }
+
+        /**
          * Validates PIN/Password and returns the validation result.
          *
          * @param password the raw password the user typed in
          * @return the validation result.
          */
-        private int validatePassword(String password) {
+        @VisibleForTesting
+        int validatePassword(String password) {
             int errorCode = NO_ERROR;
             final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
-
+            mergeMinComplexityAndDpmRequirements(metrics.quality);
 
             if (password.length() < mPasswordMinLength) {
                 if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
@@ -668,14 +725,25 @@
                 errorCode |= TOO_LONG;
             } else {
                 // The length requirements are fulfilled.
-                final int dpmQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
-                if (dpmQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX &&
-                        metrics.numeric == password.length()) {
+                if (!mPasswordNumSequenceAllowed
+                        && !requiresLettersOrSymbols()
+                        && metrics.numeric == password.length()) {
                     // Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
-                    // if DevicePolicyManager requires a complex numeric password. There can be
-                    // two cases in the UI: 1. User chooses to enroll a PIN, 2. User chooses to
-                    // enroll a password but enters a numeric-only pin. We should carry out the
-                    // sequence check in both cases.
+                    // if DevicePolicyManager or min password complexity requires a complex numeric
+                    // password. There can be two cases in the UI: 1. User chooses to enroll a
+                    // PIN, 2. User chooses to enroll a password but enters a numeric-only pin. We
+                    // should carry out the sequence check in both cases.
+                    //
+                    // Conditions for the !requiresLettersOrSymbols() to be necessary:
+                    // - DPM requires NUMERIC_COMPLEX
+                    // - min complexity not NONE, user picks PASSWORD type so ALPHABETIC or
+                    // ALPHANUMERIC is required
+                    // Imagine user has entered "12345678", if we don't skip the sequence check, the
+                    // validation result would show both "requires a letter" and "sequence not
+                    // allowed", while the only requirement the user needs to know is "requires a
+                    // letter" because once the user has fulfilled the alphabetic requirement, the
+                    // password would not be containing only digits so this check would not be
+                    // performed anyway.
                     final int sequence = PasswordMetrics.maxLengthSequence(password);
                     if (sequence > PasswordMetrics.MAX_ALLOWED_SEQUENCE) {
                         errorCode |= CONTAIN_SEQUENTIAL_DIGITS;
@@ -706,43 +774,24 @@
                 }
             }
 
-            // Check the requirements one by one.
-            for (int i = 0; i < mPasswordRequirements.length; i++) {
-                int passwordRestriction = mPasswordRequirements[i];
-                switch (passwordRestriction) {
-                    case MIN_LETTER_IN_PASSWORD:
-                        if (metrics.letters < mPasswordMinLetters) {
-                            errorCode |= NOT_ENOUGH_LETTER;
-                        }
-                        break;
-                    case MIN_UPPER_LETTERS_IN_PASSWORD:
-                        if (metrics.upperCase < mPasswordMinUpperCase) {
-                            errorCode |= NOT_ENOUGH_UPPER_CASE;
-                        }
-                        break;
-                    case MIN_LOWER_LETTERS_IN_PASSWORD:
-                        if (metrics.lowerCase < mPasswordMinLowerCase) {
-                            errorCode |= NOT_ENOUGH_LOWER_CASE;
-                        }
-                        break;
-                    case MIN_SYMBOLS_IN_PASSWORD:
-                        if (metrics.symbols < mPasswordMinSymbols) {
-                            errorCode |= NOT_ENOUGH_SYMBOLS;
-                        }
-                        break;
-                    case MIN_NUMBER_IN_PASSWORD:
-                        if (metrics.numeric < mPasswordMinNumeric) {
-                            errorCode |= NOT_ENOUGH_DIGITS;
-                        }
-                        break;
-                    case MIN_NON_LETTER_IN_PASSWORD:
-                        if (metrics.nonLetter < mPasswordMinNonLetter) {
-                            errorCode |= NOT_ENOUGH_NON_LETTER;
-                        }
-                        break;
-                }
+            if (metrics.letters < mPasswordMinLetters) {
+                errorCode |= NOT_ENOUGH_LETTER;
             }
-
+            if (metrics.upperCase < mPasswordMinUpperCase) {
+                errorCode |= NOT_ENOUGH_UPPER_CASE;
+            }
+            if (metrics.lowerCase < mPasswordMinLowerCase) {
+                errorCode |= NOT_ENOUGH_LOWER_CASE;
+            }
+            if (metrics.symbols < mPasswordMinSymbols) {
+                errorCode |= NOT_ENOUGH_SYMBOLS;
+            }
+            if (metrics.numeric < mPasswordMinNumeric) {
+                errorCode |= NOT_ENOUGH_DIGITS;
+            }
+            if (metrics.nonLetter < mPasswordMinNonLetter) {
+                errorCode |= NOT_ENOUGH_NON_LETTER;
+            }
             return errorCode;
         }
 
diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java
index 8d0fa60..32e8eaf 100644
--- a/src/com/android/settings/password/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java
@@ -46,6 +46,18 @@
     public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
 
     /**
+     * Intent extra for passing the requested min password complexity to later steps in the set new
+     * screen lock flow.
+     */
+    public static final String EXTRA_KEY_REQUESTED_MIN_COMPLEXITY = "requested_min_complexity";
+
+    /**
+     * Intent extra for passing the label of the calling app to later steps in the set new screen
+     * lock flow.
+     */
+    public static final String EXTRA_KEY_CALLER_APP_NAME = "caller_app_name";
+
+    /**
      * When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
      * controls if we relax the enforcement of
      * {@link Utils#enforceSameOwner(android.content.Context, int)}.
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
index 5eb1f32..0d9b21d 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
@@ -136,6 +136,10 @@
         Intent intent = getIntent();
         mTitle = intent.getStringExtra(KeyguardManager.EXTRA_TITLE);
         mDetails = intent.getStringExtra(KeyguardManager.EXTRA_DESCRIPTION);
+
+        final boolean requireConfirmation =
+                !intent.getBooleanExtra(KeyguardManager.EXTRA_USE_IMPLICIT, true);
+
         String alternateButton = intent.getStringExtra(
                 KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
         boolean frp = KeyguardManager.ACTION_CONFIRM_FRP_CREDENTIAL.equals(intent.getAction());
@@ -170,7 +174,7 @@
                 && !lockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
             mCredentialMode = CREDENTIAL_MANAGED;
             if (isBiometricAllowed(effectiveUserId)) {
-                showBiometricPrompt();
+                showBiometricPrompt(requireConfirmation);
                 launchedBiometric = true;
             } else {
                 showConfirmCredentials();
@@ -181,7 +185,7 @@
             if (isBiometricAllowed(effectiveUserId)) {
                 // Don't need to check if biometrics / pin/pattern/pass are enrolled. It will go to
                 // onAuthenticationError and do the right thing automatically.
-                showBiometricPrompt();
+                showBiometricPrompt(requireConfirmation);
                 launchedBiometric = true;
             } else {
                 showConfirmCredentials();
@@ -242,7 +246,7 @@
                 && !isBiometricDisabledByAdmin(effectiveUserId);
     }
 
-    private void showBiometricPrompt() {
+    private void showBiometricPrompt(boolean requireConfirmation) {
         mBiometricManager.setActiveUser(mUserId);
 
         mBiometricFragment = (BiometricFragment) getSupportFragmentManager()
@@ -255,6 +259,7 @@
                     .setSubtitle(mDetails)
                     .setNegativeButtonText(getResources()
                             .getString(R.string.confirm_device_credential_use_alternate_method))
+                    .setRequireConfirmation(requireConfirmation)
                     .build();
             mBiometricFragment = BiometricFragment.newInstance(info);
             newFragment = true;
diff --git a/src/com/android/settings/password/PasswordUtils.java b/src/com/android/settings/password/PasswordUtils.java
new file mode 100644
index 0000000..5f118cf
--- /dev/null
+++ b/src/com/android/settings/password/PasswordUtils.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 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.settings.password;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.settings.Utils;
+
+public final class PasswordUtils extends com.android.settingslib.Utils {
+
+    private static final String TAG = "Settings";
+
+    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
+
+    /**
+     * Returns whether the uid which the activity with {@code activityToken} is launched from has
+     * been granted the {@code permission}.
+     */
+    public static boolean isCallingAppPermitted(Context context, IBinder activityToken,
+            String permission) {
+        try {
+            return context.checkPermission(permission, /* pid= */ -1,
+                    ActivityManager.getService().getLaunchedFromUid(activityToken))
+                    == PackageManager.PERMISSION_GRANTED;
+        } catch (RemoteException e) {
+            Log.v(TAG, "Could not talk to activity manager.", e);
+            return false;
+        }
+    }
+
+    /**
+     * Returns the label of the package which the activity with {@code activityToken} is launched
+     * from or {@code null} if it is launched from the settings app itself.
+     */
+    @Nullable
+    public static CharSequence getCallingAppLabel(Context context, IBinder activityToken) {
+        String pkg = getCallingAppPackageName(activityToken);
+        if (pkg == null || pkg.equals(SETTINGS_PACKAGE_NAME)) {
+            return null;
+        }
+
+        return Utils.getApplicationLabel(context, pkg);
+    }
+
+    /**
+     * Returns the package name which the activity with {@code activityToken} is launched from.
+     */
+    @Nullable
+    private static String getCallingAppPackageName(IBinder activityToken) {
+        String pkg = null;
+        try {
+            pkg = ActivityManager.getService().getLaunchedFromPackage(activityToken);
+        } catch (RemoteException e) {
+            Log.v(TAG, "Could not talk to activity manager.", e);
+        }
+        return pkg;
+    }
+
+    /** Crashes the calling application and provides it with {@code message}. */
+    public static void crashCallingApplication(IBinder activityToken, String message) {
+        IActivityManager am = ActivityManager.getService();
+        try {
+            int uid = am.getLaunchedFromUid(activityToken);
+            int userId = UserHandle.getUserId(uid);
+            am.crashApplication(
+                    uid,
+                    /* initialPid= */ -1,
+                    getCallingAppPackageName(activityToken),
+                    userId,
+                    message);
+        } catch (RemoteException e) {
+            Log.v(TAG, "Could not talk to activity manager.", e);
+        }
+    }
+}
diff --git a/src/com/android/settings/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java
index 99f67cb..8ea8514 100644
--- a/src/com/android/settings/password/SetNewPasswordActivity.java
+++ b/src/com/android/settings/password/SetNewPasswordActivity.java
@@ -16,13 +16,22 @@
 
 package com.android.settings.password;
 
+import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
 
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
+import android.app.admin.PasswordMetrics;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.util.Log;
 
 import com.android.settings.Utils;
@@ -37,6 +46,21 @@
     private String mNewPasswordAction;
     private SetNewPasswordController mSetNewPasswordController;
 
+    /**
+     * From intent extra {@link DevicePolicyManager#EXTRA_PASSWORD_COMPLEXITY}.
+     *
+     * <p>This is used only if caller has the required permission and activity is launched by
+     * {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD}.
+     */
+    private @PasswordComplexity int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
+
+    /**
+     * Label of the app which launches this activity.
+     *
+     * <p>Value would be {@code null} if launched from settings app.
+     */
+    private String mCallerAppName = null;
+
     @Override
     protected void onCreate(Bundle savedState) {
         super.onCreate(savedState);
@@ -48,6 +72,25 @@
             finish();
             return;
         }
+
+        IBinder activityToken = getActivityToken();
+        mCallerAppName = (String) PasswordUtils.getCallingAppLabel(this, activityToken);
+        if (ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
+                && getIntent().hasExtra(EXTRA_PASSWORD_COMPLEXITY)) {
+            boolean hasPermission = PasswordUtils.isCallingAppPermitted(
+                    this, activityToken, GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+            if (hasPermission) {
+                mRequestedMinComplexity = PasswordMetrics.sanitizeComplexityLevel(getIntent()
+                        .getIntExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_NONE));
+            } else {
+                PasswordUtils.crashCallingApplication(activityToken,
+                        "Must have permission " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY
+                                + " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
+                finish();
+                return;
+            }
+        }
+
         mSetNewPasswordController = SetNewPasswordController.create(
                 this, this, getIntent(), getActivityToken());
         mSetNewPasswordController.dispatchSetNewPasswordIntent();
@@ -60,6 +103,12 @@
                 : new Intent(this, ChooseLockGeneric.class);
         intent.setAction(mNewPasswordAction);
         intent.putExtras(chooseLockFingerprintExtras);
+        if (mCallerAppName != null) {
+            intent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
+        }
+        if (mRequestedMinComplexity != PASSWORD_COMPLEXITY_NONE) {
+            intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, mRequestedMinComplexity);
+        }
         startActivity(intent);
         finish();
     }
diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java
index a0f8bae..33c3edb 100644
--- a/src/com/android/settings/password/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/password/SetupChooseLockGeneric.java
@@ -16,11 +16,17 @@
 
 package com.android.settings.password;
 
+import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.UserHandle;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -48,6 +54,7 @@
  * Other changes should be done to ChooseLockGeneric class instead and let this class inherit
  * those changes.
  */
+// TODO(b/123225425): Restrict SetupChooseLockGeneric to be accessible by SUW only
 public class SetupChooseLockGeneric extends ChooseLockGeneric {
 
     private static final String KEY_UNLOCK_SET_DO_LATER = "unlock_set_do_later";
@@ -71,6 +78,20 @@
     @Override
     protected void onCreate(Bundle savedInstance) {
         super.onCreate(savedInstance);
+
+        if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) {
+            IBinder activityToken = getActivityToken();
+            boolean hasPermission = PasswordUtils.isCallingAppPermitted(
+                    this, activityToken, GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+            if (!hasPermission) {
+                PasswordUtils.crashCallingApplication(activityToken,
+                        "Must have permission " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY
+                                + " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
+                finish();
+                return;
+            }
+        }
+
         LinearLayout layout = (LinearLayout) findViewById(R.id.content_parent);
         layout.setFitsSystemWindows(false);
     }
diff --git a/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java b/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
index 3fac672..e43140f 100644
--- a/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
+++ b/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
@@ -76,6 +76,7 @@
                 .setEmptyText(R.string.permission_bar_chart_empty_text)
                 .setDetailsOnClickListener((View v) -> {
                     final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
+                    intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
                     mContext.startActivity(intent);
                 })
                 .build();
@@ -102,7 +103,7 @@
 
     private void retrievePermissionUsageData() {
         mContext.getSystemService(PermissionControllerManager.class).getPermissionUsages(
-                false /* countSystem */, (int) DAYS.toSeconds(1),
+                false /* countSystem */, (int) DAYS.toMillis(1),
                 mContext.getMainExecutor() /* executor */, this /* callback */);
     }
 
@@ -111,6 +112,9 @@
             return null;
         }
 
+        // STOPSHIP: Ignore the STORAGE group since it's going away.
+        usageInfos.removeIf(usage -> usage.getName().equals("android.permission-group.STORAGE"));
+
         final BarViewInfo[] barViewInfos = new BarViewInfo[
                 Math.min(BarChartPreference.MAXIMUM_BAR_VIEWS, usageInfos.size())];
 
diff --git a/src/com/android/settings/slices/SliceBackgroundWorker.java b/src/com/android/settings/slices/SliceBackgroundWorker.java
index 284fd23..6df45ba 100644
--- a/src/com/android/settings/slices/SliceBackgroundWorker.java
+++ b/src/com/android/settings/slices/SliceBackgroundWorker.java
@@ -59,10 +59,6 @@
         mUri = uri;
     }
 
-    protected Uri getUri() {
-        return mUri;
-    }
-
     /**
      * Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link Uri}
      * if exists
@@ -148,7 +144,14 @@
 
         if (needNotify) {
             mCachedResults = results;
-            mContext.getContentResolver().notifyChange(mUri, null);
+            notifySliceChange();
         }
     }
-}
+
+    /**
+     * Notify that data was updated and attempt to sync changes to the Slice.
+     */
+    protected void notifySliceChange() {
+        mContext.getContentResolver().notifyChange(mUri, null);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/slices/SlicePreferenceController.java b/src/com/android/settings/slices/SlicePreferenceController.java
index d7fcc18..89294c7 100644
--- a/src/com/android/settings/slices/SlicePreferenceController.java
+++ b/src/com/android/settings/slices/SlicePreferenceController.java
@@ -82,6 +82,8 @@
 
     @Override
     public void onChanged(Slice slice) {
-        mSlicePreference.onSliceUpdated(slice);
+        if (slice != null) {
+            mSlicePreference.onSliceUpdated(slice);
+        }
     }
 }
diff --git a/src/com/android/settings/vpn2/AppDialogFragment.java b/src/com/android/settings/vpn2/AppDialogFragment.java
index 0d0022f..2f9cd7a 100644
--- a/src/com/android/settings/vpn2/AppDialogFragment.java
+++ b/src/com/android/settings/vpn2/AppDialogFragment.java
@@ -164,7 +164,8 @@
         final int userId = getUserId();
         try {
             if (mPackageInfo.packageName.equals(VpnUtils.getConnectedPackage(mService, userId))) {
-                mService.setAlwaysOnVpnPackage(userId, null, /* lockdownEnabled */ false);
+                mService.setAlwaysOnVpnPackage(userId, null, /* lockdownEnabled */ false,
+                        /* lockdownWhitelist */ null);
                 mService.prepareVpn(mPackageInfo.packageName, VpnConfig.LEGACY_VPN, userId);
             }
         } catch (RemoteException e) {
diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java
index 1571216..5f46446 100644
--- a/src/com/android/settings/vpn2/AppManagementFragment.java
+++ b/src/com/android/settings/vpn2/AppManagementFragment.java
@@ -225,7 +225,7 @@
 
     private boolean setAlwaysOnVpn(boolean isEnabled, boolean isLockdown) {
         return mConnectivityManager.setAlwaysOnVpnPackageForUser(mUserId,
-                isEnabled ? mPackageName : null, isLockdown);
+                isEnabled ? mPackageName : null, isLockdown, /* lockdownWhitelist */ null);
     }
 
     private void updateUI() {
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index ec927ae..01b20f0 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -199,7 +199,7 @@
 
             final ConnectivityManager conn = ConnectivityManager.from(mContext);
             conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null,
-                    /* lockdownEnabled */ false);
+                    /* lockdownEnabled */ false, /* lockdownWhitelist */ null);
             VpnUtils.setLockdownVpn(mContext, profile.key);
         } else {
             // update only if lockdown vpn has been changed
diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
index 1c79c1d..88fa8b2 100644
--- a/src/com/android/settings/wifi/slice/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -292,11 +292,12 @@
 
         @Override
         public void onWifiStateChanged(int state) {
-            mContext.getContentResolver().notifyChange(getUri(), null);
+            notifySliceChange();
         }
 
         @Override
         public void onConnectedChanged() {
+            notifySliceChange();
         }
 
         @Override
diff --git a/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
index bf4dec6..c6a48a8 100644
--- a/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.ArraySet;
 
 import com.android.settingslib.RestrictedSwitchPreference;
 
@@ -45,6 +46,9 @@
 import org.robolectric.Shadows;
 import org.robolectric.shadows.ShadowDevicePolicyManager;
 
+import java.util.Arrays;
+import java.util.Collections;
+
 @RunWith(RobolectricTestRunner.class)
 public class CrossProfileCalendarPreferenceControllerTest {
 
@@ -123,7 +127,17 @@
     @Test
     public void updateState_somePackagesAllowed_preferenceShouldNotBeDisabled() throws Exception {
         dpm.setProfileOwner(TEST_COMPONENT_NAME);
-        dpm.addCrossProfileCalendarPackage(TEST_COMPONENT_NAME, TEST_PACKAGE_NAME);
+        dpm.setCrossProfileCalendarPackages(TEST_COMPONENT_NAME,
+                Collections.singleton(TEST_PACKAGE_NAME));
+
+        mController.updateState(mPreference);
+        verify(mPreference).setDisabledByAdmin(null);
+    }
+
+    @Test
+    public void updateState_allPackagesAllowed_preferenceShouldNotBeDisabled() throws Exception {
+        dpm.setProfileOwner(TEST_COMPONENT_NAME);
+        dpm.setCrossProfileCalendarPackages(TEST_COMPONENT_NAME, null);
 
         mController.updateState(mPreference);
         verify(mPreference).setDisabledByAdmin(null);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
index 1da97f5..b6bbe8a 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.settings.connecteddevice.usb;
 
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
@@ -101,7 +103,8 @@
         final Intent intent = new Intent();
         intent.setAction(UsbManager.ACTION_USB_PORT_CHANGED);
         final UsbPortStatus status = new UsbPortStatus(0, POWER_ROLE_SINK,
-                DATA_ROLE_DEVICE, 0);
+                DATA_ROLE_DEVICE, 0, CONTAMINANT_PROTECTION_NONE,
+                CONTAMINANT_DETECTION_NOT_SUPPORTED);
         intent.putExtra(UsbManager.EXTRA_PORT_STATUS, status);
 
         mReceiver.onReceive(mContext, intent);
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayActivationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayActivationPreferenceControllerTest.java
index 6e23e5f..e666d61 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayActivationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayActivationPreferenceControllerTest.java
@@ -15,12 +15,11 @@
 package com.android.settings.display;
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.provider.Settings.Secure;
+import android.hardware.display.ColorDisplayManager;
 import android.view.View;
 
 import androidx.preference.PreferenceScreen;
@@ -47,17 +46,19 @@
     private PreferenceScreen mScreen;
     private LayoutPreference mPreference;
     private Context mContext;
-    private NightDisplayActivationPreferenceController mController;
+    private ColorDisplayManager mColorDisplayManager;
+    private NightDisplayActivationPreferenceController mPreferenceController;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
+        mColorDisplayManager = mContext.getSystemService(ColorDisplayManager.class);
         mPreference = new LayoutPreference(mContext, R.layout.night_display_activation_button);
         when(mScreen.findPreference(anyString())).thenReturn(mPreference);
-        mController = new NightDisplayActivationPreferenceController(mContext,
+        mPreferenceController = new NightDisplayActivationPreferenceController(mContext,
             "night_display_activation");
-        mController.displayPreference(mScreen);
+        mPreferenceController.displayPreference(mScreen);
     }
 
     @After
@@ -69,14 +70,14 @@
     public void isAvailable_configuredAvailable() {
         SettingsShadowResources.overrideResource(
                 com.android.internal.R.bool.config_nightDisplayAvailable, true);
-        assertThat(mController.isAvailable()).isTrue();
+        assertThat(mPreferenceController.isAvailable()).isTrue();
     }
 
     @Test
     public void isAvailable_configuredUnavailable() {
         SettingsShadowResources.overrideResource(
                 com.android.internal.R.bool.config_nightDisplayAvailable, false);
-        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mPreferenceController.isAvailable()).isFalse();
     }
 
     @Test
@@ -95,25 +96,23 @@
 
     @Test
     public void onClick_activates() {
-        Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 0);
+        mColorDisplayManager.setNightDisplayActivated(false);
 
         final View view = mPreference.findViewById(R.id.night_display_turn_on_button);
         assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
         view.performClick();
 
-        assertThat(Secure.getInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, -1))
-                .isEqualTo(1);
+        assertThat(mColorDisplayManager.isNightDisplayActivated()).isEqualTo(true);
     }
 
     @Test
     public void onClick_deactivates() {
-        Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 1);
+        mColorDisplayManager.setNightDisplayActivated(true);
 
-        final View view = mPreference.findViewById(R.id.night_display_turn_on_button);
+        final View view = mPreference.findViewById(R.id.night_display_turn_off_button);
         assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
         view.performClick();
 
-        assertThat(Secure.getInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, -1))
-                .isEqualTo(0);
+        assertThat(mColorDisplayManager.isNightDisplayActivated()).isEqualTo(false);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java
index 85d497a..de5c81e 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java
@@ -17,9 +17,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
 import android.provider.Settings.Secure;
 
-import com.android.internal.app.ColorDisplayController;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
 
 import org.junit.After;
@@ -66,8 +66,8 @@
     @Test
     public void onPreferenceChange_changesAutoMode() {
         mController.onPreferenceChange(null,
-                String.valueOf(ColorDisplayController.AUTO_MODE_TWILIGHT));
-        assertThat(Secure.getInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE, -1))
-                .isEqualTo(ColorDisplayController.AUTO_MODE_TWILIGHT);
+                String.valueOf(ColorDisplayManager.AUTO_MODE_TWILIGHT));
+        assertThat(mContext.getSystemService(ColorDisplayManager.class).getNightDisplayAutoMode())
+                .isEqualTo(ColorDisplayManager.AUTO_MODE_TWILIGHT);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayIntensityPreferenceControllerTest.java
index 2edec2e..2e2d631 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayIntensityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayIntensityPreferenceControllerTest.java
@@ -17,10 +17,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
 import android.provider.Settings.Secure;
-
 import com.android.settings.testutils.shadow.SettingsShadowResources;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -33,69 +32,69 @@
 @Config(shadows = SettingsShadowResources.class)
 public class NightDisplayIntensityPreferenceControllerTest {
 
-    private Context mContext;
-    private NightDisplayIntensityPreferenceController mController;
+  private Context mContext;
+  private NightDisplayIntensityPreferenceController mPreferenceController;
 
-    @Before
-    public void setUp() {
-        mContext = RuntimeEnvironment.application;
-        mController = new NightDisplayIntensityPreferenceController(mContext,
-            "night_display_temperature");
-    }
+  @Before
+  public void setUp() {
+    mContext = RuntimeEnvironment.application;
+    mPreferenceController = new NightDisplayIntensityPreferenceController(mContext,
+        "night_display_temperature");
+  }
 
-    @After
-    public void tearDown() {
-        SettingsShadowResources.reset();
-    }
+  @After
+  public void tearDown() {
+    SettingsShadowResources.reset();
+  }
 
-    @Test
-    public void isAvailable_configuredAvailable_isActivated_available() {
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.bool.config_nightDisplayAvailable, true);
-        Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 1);
-        assertThat(mController.isAvailable()).isTrue();
-    }
+  @Test
+  public void isAvailable_configuredAvailable_isActivated_available() {
+    SettingsShadowResources.overrideResource(
+        com.android.internal.R.bool.config_nightDisplayAvailable, true);
+    Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 1);
+    assertThat(mPreferenceController.isAvailable()).isTrue();
+  }
 
-    @Test
-    public void isAvailable_configuredAvailable_isNotActivated_available() {
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.bool.config_nightDisplayAvailable, true);
-        Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 0);
-        assertThat(mController.isAvailable()).isTrue();
-    }
+  @Test
+  public void isAvailable_configuredAvailable_isNotActivated_available() {
+    SettingsShadowResources.overrideResource(
+        com.android.internal.R.bool.config_nightDisplayAvailable, true);
+    Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 0);
+    assertThat(mPreferenceController.isAvailable()).isTrue();
+  }
 
-    @Test
-    public void isAvailable_configuredUnavailable_unavailable() {
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.bool.config_nightDisplayAvailable, false);
-        assertThat(mController.isAvailable()).isFalse();
-    }
+  @Test
+  public void isAvailable_configuredUnavailable_unavailable() {
+    SettingsShadowResources.overrideResource(
+        com.android.internal.R.bool.config_nightDisplayAvailable, false);
+    assertThat(mPreferenceController.isAvailable()).isFalse();
+  }
 
-    @Test
-    public void onPreferenceChange_changesTemperature() {
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.integer.config_nightDisplayColorTemperatureMin, 2950);
-        SettingsShadowResources.overrideResource(
-                com.android.internal.R.integer.config_nightDisplayColorTemperatureMax, 3050);
-        // A slider-adjusted "20" here would be 1/5 from the left / least-intense, i.e. 3030.
-        mController.onPreferenceChange(null, 20);
+  @Test
+  public void onPreferenceChange_changesTemperature() {
+    SettingsShadowResources.overrideResource(
+        com.android.internal.R.integer.config_nightDisplayColorTemperatureMin, 2950);
+    SettingsShadowResources.overrideResource(
+        com.android.internal.R.integer.config_nightDisplayColorTemperatureMax, 3050);
+    // A slider-adjusted "20" here would be 1/5 from the left / least-intense, i.e. 3030.
+    mPreferenceController.onPreferenceChange(null, 20);
 
-        assertThat(Secure.getInt(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, -1))
-                .isEqualTo(3030);
-    }
+    assertThat(
+        mContext.getSystemService(ColorDisplayManager.class).getNightDisplayColorTemperature())
+        .isEqualTo(3030);
+  }
 
-    @Test
-    public void isSliceableCorrectKey_returnsTrue() {
-        final NightDisplayIntensityPreferenceController controller =
-                new NightDisplayIntensityPreferenceController(mContext,"night_display_temperature");
-        assertThat(controller.isSliceable()).isTrue();
-    }
+  @Test
+  public void isSliceableCorrectKey_returnsTrue() {
+    final NightDisplayIntensityPreferenceController controller =
+        new NightDisplayIntensityPreferenceController(mContext, "night_display_temperature");
+    assertThat(controller.isSliceable()).isTrue();
+  }
 
-    @Test
-    public void isSliceableIncorrectKey_returnsFalse() {
-        final NightDisplayIntensityPreferenceController controller =
-                new NightDisplayIntensityPreferenceController(mContext, "bad_key");
-        assertThat(controller.isSliceable()).isFalse();
-    }
+  @Test
+  public void isSliceableIncorrectKey_returnsFalse() {
+    final NightDisplayIntensityPreferenceController controller =
+        new NightDisplayIntensityPreferenceController(mContext, "bad_key");
+    assertThat(controller.isSliceable()).isFalse();
+  }
 }
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
index c066e6c..eeaae67f 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
@@ -3,12 +3,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.app.Application;
-import android.provider.Settings.Secure;
-
-import com.android.internal.app.ColorDisplayController;
+import android.hardware.display.ColorDisplayManager;
 import com.android.settings.R;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
-
 import org.junit.After;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -28,32 +25,32 @@
   @Test
   public void nightDisplaySuggestion_isNotCompleted_ifAutoModeDisabled() {
     final Application context = RuntimeEnvironment.application;
-    Secure.putInt(context.getContentResolver(),
-        Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_DISABLED);
+    context.getSystemService(ColorDisplayManager.class)
+        .setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_DISABLED);
     assertThat(NightDisplayPreferenceController.isSuggestionComplete(context)).isFalse();
   }
 
   @Test
   public void nightDisplaySuggestion_isCompleted_ifAutoModeCustom() {
     final Application context = RuntimeEnvironment.application;
-    Secure.putInt(context.getContentResolver(),
-        Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_CUSTOM);
+    context.getSystemService(ColorDisplayManager.class)
+        .setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
     assertThat(NightDisplayPreferenceController.isSuggestionComplete(context)).isTrue();
   }
 
   @Test
   public void nightDisplaySuggestion_isCompleted_ifAutoModeTwilight() {
     final Application context = RuntimeEnvironment.application;
-    Secure.putInt(context.getContentResolver(),
-        Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_TWILIGHT);
+    context.getSystemService(ColorDisplayManager.class)
+        .setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_TWILIGHT);
     assertThat(NightDisplayPreferenceController.isSuggestionComplete(context)).isTrue();
   }
 
   @Test
-  public void nightDisplaySuggestion_isCompleted_ifDisabled() {
+  public void nightDisplaySuggestion_isCompleted_ifSuggestionDisabled() {
     final Application context = RuntimeEnvironment.application;
-    Secure.putInt(context.getContentResolver(),
-            Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_DISABLED);
+    context.getSystemService(ColorDisplayManager.class)
+        .setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_DISABLED);
     SettingsShadowResources.overrideResource(R.bool.config_night_light_suggestion_enabled, false);
     assertThat(NightDisplayPreferenceController.isSuggestionComplete(context)).isTrue();
   }
diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
index 3b33558..8cba1de 100644
--- a/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
@@ -36,6 +36,7 @@
 import com.android.settingslib.widget.LayoutPreference;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -77,6 +78,7 @@
 
     /** Verifies the title text, details text are correct, and the click listener is set. */
     @Test
+    @Ignore
     public void updateState_whenAppListIsEmpty_shouldDisplayTitleTextAndDetailsText() {
         doReturn(new ArrayList<>()).when(mRecentLocationApps).getAppListSorted();
         mController.displayPreference(mScreen);
diff --git a/tests/robotests/src/com/android/settings/network/telephony/DefaultSubscriptionControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/DefaultSubscriptionControllerTest.java
new file mode 100644
index 0000000..f7a2567
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/telephony/DefaultSubscriptionControllerTest.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2019 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.settings.network.telephony;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Arrays;
+
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class DefaultSubscriptionControllerTest {
+    @Mock
+    private SubscriptionManager mManager;
+    @Mock
+    private PreferenceScreen mScreen;
+
+    private ListPreference mListPreference;
+    private Context mContext;
+    private DefaultSubscriptionController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mManager);
+        final String key = "prefkey";
+        mController = spy(new TestDefaultSubscriptionController(mContext, key));
+        mListPreference = spy(new ListPreference(mContext));
+        when(mScreen.findPreference(key)).thenReturn(mListPreference);
+    }
+
+    @After
+    public void tearDown() {
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
+    }
+
+    @Test
+    public void getAvailabilityStatus_onlyOneSubscription_notAvailable() {
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(
+                createMockSub(1, "sub1")));
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void getAvailabilityStatus_twoSubscriptions_isAvailable() {
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(
+                createMockSub(1, "sub1"),
+                createMockSub(2, "sub2")));
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void displayPreference_twoSubscriptionsSub1Default_correctListPreferenceValues() {
+        final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+        final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+        mController.displayPreference(mScreen);
+
+        final CharSequence entry = mListPreference.getEntry();
+        final String value = mListPreference.getValue();
+        assertThat(entry).isEqualTo("sub1");
+        assertThat(value).isEqualTo("111");
+
+        final CharSequence[] entries = mListPreference.getEntries();
+        assertThat(entries.length).isEqualTo(3);
+        assertThat(entries[0]).isEqualTo("sub1");
+        assertThat(entries[1]).isEqualTo("sub2");
+        assertThat(entries[2]).isEqualTo(mContext.getString(R.string.calls_and_sms_ask_every_time));
+
+        final CharSequence[] entryValues = mListPreference.getEntryValues();
+        assertThat(entryValues.length).isEqualTo(3);
+        assertThat(entryValues[0]).isEqualTo("111");
+        assertThat(entryValues[1]).isEqualTo("222");
+        assertThat(entryValues[2]).isEqualTo(
+                Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+    }
+
+    @Test
+    public void displayPreference_twoSubscriptionsSub2Default_correctListPreferenceValues() {
+        final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+        final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        doReturn(sub2.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+        mController.displayPreference(mScreen);
+
+        final CharSequence entry = mListPreference.getEntry();
+        final String value = mListPreference.getValue();
+        assertThat(entry).isEqualTo("sub2");
+        assertThat(value).isEqualTo("222");
+
+        final CharSequence[] entries = mListPreference.getEntries();
+        assertThat(entries.length).isEqualTo(3);
+        assertThat(entries[0]).isEqualTo("sub1");
+        assertThat(entries[1]).isEqualTo("sub2");
+        assertThat(entries[2]).isEqualTo(mContext.getString(R.string.calls_and_sms_ask_every_time));
+
+        final CharSequence[] entryValues = mListPreference.getEntryValues();
+        assertThat(entryValues.length).isEqualTo(3);
+        assertThat(entryValues[0]).isEqualTo("111");
+        assertThat(entryValues[1]).isEqualTo("222");
+        assertThat(entryValues[2]).isEqualTo(
+                Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+    }
+
+    @Test
+    public void onPreferenceChange_prefChangedToSub2_callbackCalledCorrectly() {
+        final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+        final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+        mController.displayPreference(mScreen);
+        mListPreference.setValue("222");
+        mController.onPreferenceChange(mListPreference, "222");
+        verify(mController).setDefaultSubscription(eq(222));
+    }
+
+    @Test
+    public void onPreferenceChange_prefChangedToAlwaysAsk_callbackCalledCorrectly() {
+        final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+        final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+        mController.displayPreference(mScreen);
+        mListPreference.setValue(Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+        mController.onPreferenceChange(mListPreference,
+                Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+        verify(mController).setDefaultSubscription(
+                eq(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+    }
+
+    @Test
+    public void onSubscriptionsChanged_twoSubscriptionsDefaultChanges_selectedEntryGetsUpdated() {
+        final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+        final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+        mController.displayPreference(mScreen);
+        assertThat( mListPreference.getEntry()).isEqualTo("sub1");
+        assertThat(mListPreference.getValue()).isEqualTo("111");
+
+        doReturn(sub2.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+        mController.onSubscriptionsChanged();
+        assertThat( mListPreference.getEntry()).isEqualTo("sub2");
+        assertThat(mListPreference.getValue()).isEqualTo("222");
+    }
+
+    @Test
+    public void onSubscriptionsChanged_goFromTwoSubscriptionsToOne_prefDisappears() {
+        final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+        final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+        mController.displayPreference(mScreen);
+        assertThat(mController.isAvailable()).isTrue();
+        assertThat(mListPreference.isVisible()).isTrue();
+
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+        mController.onSubscriptionsChanged();
+
+        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mListPreference.isVisible()).isFalse();
+    }
+
+    @Test
+    public void onSubscriptionsChanged_goFromOneSubscriptionToTwo_prefAppears() {
+        final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+        final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+        doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+        mController.displayPreference(mScreen);
+        assertThat(mController.isAvailable()).isFalse();
+        assertThat(mListPreference.isVisible()).isFalse();
+
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        mController.onSubscriptionsChanged();
+
+        assertThat(mController.isAvailable()).isTrue();
+        assertThat(mListPreference.isVisible()).isTrue();
+    }
+
+    @Test
+    public void onSubscriptionsChanged_goFromTwoToThreeSubscriptions_listGetsUpdated() {
+        final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+        final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+        final SubscriptionInfo sub3 = createMockSub(333, "sub3");
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+        mController.displayPreference(mScreen);
+        assertThat(mListPreference.getEntries().length).isEqualTo(3);
+
+        SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2, sub3));
+        mController.onSubscriptionsChanged();
+
+        assertThat(mController.isAvailable()).isTrue();
+        assertThat(mListPreference.isVisible()).isTrue();
+        final CharSequence[] entries = mListPreference.getEntries();
+        final CharSequence[] entryValues = mListPreference.getEntryValues();
+        assertThat(entries.length).isEqualTo(4);
+        assertThat(entries[0].toString()).isEqualTo("sub1");
+        assertThat(entries[1].toString()).isEqualTo("sub2");
+        assertThat(entries[2].toString()).isEqualTo("sub3");
+        assertThat(entries[3].toString()).isEqualTo(
+                mContext.getString(R.string.calls_and_sms_ask_every_time));
+        assertThat(entryValues[0].toString()).isEqualTo("111");
+        assertThat(entryValues[1].toString()).isEqualTo("222");
+        assertThat(entryValues[2].toString()).isEqualTo("333");
+        assertThat(entryValues[3].toString()).isEqualTo(
+                Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+    }
+
+    private SubscriptionInfo createMockSub(int id, String displayName) {
+        final SubscriptionInfo sub = mock(SubscriptionInfo.class);
+        when(sub.getSubscriptionId()).thenReturn(id);
+        when(sub.getDisplayName()).thenReturn(displayName);
+        return sub;
+    }
+
+    private class TestDefaultSubscriptionController extends DefaultSubscriptionController {
+
+        public TestDefaultSubscriptionController(Context context, String preferenceKey) {
+            super(context, preferenceKey);
+        }
+
+        @Override
+        protected SubscriptionInfo getDefaultSubscriptionInfo() {
+            return null;
+        }
+
+        @Override
+        protected int getDefaultSubscriptionId() {
+            return 0;
+        }
+
+        @Override
+        protected void setDefaultSubscription(int subscriptionId) {
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
index 0240bd8..55a4224 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
@@ -85,7 +85,13 @@
     }
 
     @Test
-    public void onAttach_noCrash() {
+    public void onAttach_noV2Flag_noCrash() {
+        mFragment.onAttach(mContext);
+    }
+
+    @Test
+    public void onAttach_v2Flag_noCrash() {
+        FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, true);
         mFragment.onAttach(mContext);
     }
 
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
index cbc5765..2b7bdeb 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
@@ -16,15 +16,22 @@
 
 package com.android.settings.password;
 
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
 import static org.robolectric.RuntimeEnvironment.application;
 
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.content.ComponentName;
 
 import com.android.settings.R;
@@ -58,11 +65,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mController = new ChooseLockGenericController(
-                application,
-                0 /* userId */,
-                mDevicePolicyManager,
-                mManagedLockPasswordProvider);
+        mController = createController(PASSWORD_COMPLEXITY_NONE);
         SettingsShadowResources.overrideResource(R.bool.config_hide_none_security_option, false);
         SettingsShadowResources.overrideResource(R.bool.config_hide_swipe_security_option, false);
     }
@@ -225,4 +228,44 @@
         assertThat(upgradedQuality).named("upgradedQuality")
                 .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
     }
+
+    @Test
+    public void upgradeQuality_complexityHigh_minQualityNumericComplex() {
+        when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
+                .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+        ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_HIGH);
+
+        assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
+    }
+
+    @Test
+    public void upgradeQuality_complexityMedium_minQualityNumericComplex() {
+        when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
+                .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+        ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_MEDIUM);
+
+        assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
+    }
+
+    @Test
+    public void upgradeQuality_complexityLow_minQualitySomething() {
+        when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
+                .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+        ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_LOW);
+
+        assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+    }
+
+    private ChooseLockGenericController createController(
+            @PasswordComplexity int minPasswordComplexity) {
+        return new ChooseLockGenericController(
+                application,
+                0 /* userId */,
+                minPasswordComplexity,
+                mDevicePolicyManager,
+                mManagedLockPasswordProvider);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
index e324214..a1db12c 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -16,6 +16,15 @@
 
 package com.android.settings.password;
 
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.robolectric.RuntimeEnvironment.application;
@@ -27,8 +36,10 @@
 import android.provider.Settings.Global;
 
 import androidx.annotation.Nullable;
+import androidx.preference.Preference;
 
 import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.R;
 import com.android.settings.biometrics.BiometricEnrollBase;
 import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
 import com.android.settings.search.SearchFeatureProvider;
@@ -36,6 +47,7 @@
 import com.android.settings.testutils.shadow.ShadowStorageManager;
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settingslib.widget.FooterPreference;
 
 import org.junit.After;
 import org.junit.Before;
@@ -113,6 +125,70 @@
     }
 
     @Test
+    public void updatePreferencesOrFinish_footerPreferenceAddedHighComplexityText() {
+        ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
+        Intent intent = new Intent()
+                .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
+                .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+        initActivity(intent);
+        CharSequence expectedTitle =
+              mActivity.getString(R.string.unlock_footer_high_complexity_requested, "app name");
+
+        mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+        FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
+
+        assertThat(footer.getTitle()).isEqualTo(expectedTitle);
+    }
+
+    @Test
+    public void updatePreferencesOrFinish_footerPreferenceAddedMediumComplexityText() {
+        ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
+        Intent intent = new Intent()
+                .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
+                .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_MEDIUM);
+        initActivity(intent);
+        CharSequence expectedTitle =
+                mActivity.getString(R.string.unlock_footer_medium_complexity_requested, "app name");
+
+        mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+        FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
+
+        assertThat(footer.getTitle()).isEqualTo(expectedTitle);
+    }
+
+    @Test
+    public void updatePreferencesOrFinish_footerPreferenceAddedLowComplexityText() {
+        ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
+        Intent intent = new Intent()
+                .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
+                .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_LOW);
+        initActivity(intent);
+        CharSequence expectedTitle =
+                mActivity.getString(R.string.unlock_footer_low_complexity_requested, "app name");
+
+        mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+        FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
+
+        assertThat(footer.getTitle()).isEqualTo(expectedTitle);
+    }
+
+    @Test
+    public void updatePreferencesOrFinish_footerPreferenceAddedNoneComplexityText() {
+        ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
+        Intent intent = new Intent()
+                .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
+                .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
+        initActivity(intent);
+        CharSequence expectedTitle =
+                mActivity.getString(R.string.unlock_footer_none_complexity_requested, "app name");
+
+        mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+        FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
+
+        assertThat(footer.getTitle()).isEqualTo(expectedTitle);
+    }
+
+    @Test
     public void onActivityResult_requestcode0_shouldNotFinish() {
         initActivity(null);
 
@@ -165,6 +241,48 @@
         assertThat(mActivity.isFinishing()).isTrue();
     }
 
+    @Test
+    public void onPreferenceTreeClick_fingerprintPassesMinComplexityInfoOntoNextActivity() {
+        Intent intent = new Intent(ACTION_SET_NEW_PASSWORD)
+                .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH)
+                .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name");
+        initActivity(intent);
+
+        Preference fingerprintPref = new Preference(application);
+        fingerprintPref.setKey("unlock_skip_fingerprint");
+        boolean result = mFragment.onPreferenceTreeClick(fingerprintPref);
+
+        assertThat(result).isTrue();
+        Intent actualIntent = shadowOf(mActivity).getNextStartedActivityForResult().intent;
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
+        assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
+                .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+        assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME))
+                .isEqualTo("app name");
+    }
+
+    @Test
+    public void onPreferenceTreeClick_facePassesMinComplexityInfoOntoNextActivity() {
+        Intent intent = new Intent(ACTION_SET_NEW_PASSWORD)
+                .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH)
+                .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name");
+        initActivity(intent);
+
+        Preference facePref = new Preference(application);
+        facePref.setKey("unlock_skip_face");
+        boolean result = mFragment.onPreferenceTreeClick(facePref);
+
+        assertThat(result).isTrue();
+        Intent actualIntent = shadowOf(mActivity).getNextStartedActivityForResult().intent;
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
+        assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
+                .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+        assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME))
+                .isEqualTo("app name");
+    }
+
     private void initActivity(@Nullable Intent intent) {
         if (intent == null) {
             intent = new Intent();
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index 367cb4c..404d205 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -16,19 +16,37 @@
 
 package com.android.settings.password;
 
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
+import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
+import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.robolectric.RuntimeEnvironment.application;
 
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.content.Intent;
 import android.os.UserHandle;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.R;
 import com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment;
 import com.android.settings.password.ChooseLockPassword.IntentBuilder;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
 import com.android.settings.testutils.shadow.ShadowUtils;
 
 import com.google.android.setupdesign.GlifLayout;
@@ -44,13 +62,21 @@
 import org.robolectric.shadows.ShadowDrawable;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {SettingsShadowResources.class, ShadowUtils.class})
+@Config(shadows = {
+        SettingsShadowResources.class,
+        ShadowUtils.class,
+        ShadowDevicePolicyManager.class,
+})
 public class ChooseLockPasswordTest {
 
+    private ShadowDevicePolicyManager mShadowDpm;
+
     @Before
     public void setUp() {
         SettingsShadowResources.overrideResource(
                 com.android.internal.R.string.config_headlineFontFamily, "");
+        mShadowDpm = ShadowDevicePolicyManager.getShadow();
+        mShadowDpm.setPasswordMaximumLength(16);
     }
 
     @After
@@ -72,7 +98,7 @@
         assertThat(intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
                 .named("EXTRA_KEY_PASSWORD")
                 .isEqualTo("password");
-        assertThat(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, 0))
+        assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0))
                 .named("PASSWORD_TYPE_KEY")
                 .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
         assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
@@ -84,7 +110,7 @@
     public void intentBuilder_setChallenge_shouldAddExtras() {
         Intent intent = new IntentBuilder(application)
                 .setChallenge(12345L)
-                .setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC)
+                .setPasswordQuality(PASSWORD_QUALITY_ALPHANUMERIC)
                 .setUserId(123)
                 .build();
 
@@ -94,15 +120,214 @@
         assertThat(intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L))
                 .named("EXTRA_KEY_CHALLENGE")
                 .isEqualTo(12345L);
-        assertThat(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, 0))
+        assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0))
                 .named("PASSWORD_TYPE_KEY")
-                .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
+                .isEqualTo(PASSWORD_QUALITY_ALPHANUMERIC);
         assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
                 .named("EXTRA_USER_ID")
                 .isEqualTo(123);
     }
 
     @Test
+    public void intentBuilder_setMinComplexityMedium_hasMinComplexityExtraMedium() {
+        Intent intent = new IntentBuilder(application)
+                .setRequestedMinComplexity(PASSWORD_COMPLEXITY_MEDIUM)
+                .build();
+
+        assertThat(intent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
+        assertThat(intent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
+                .isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
+    }
+
+    @Test
+    public void intentBuilder_setMinComplexityNotCalled() {
+        Intent intent = new IntentBuilder(application).build();
+
+        assertThat(intent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_noMinPasswordComplexity() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHABETIC);
+        mShadowDpm.setPasswordMinimumLength(10);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "",
+                "Must contain at least 1 letter",
+                "Must be at least 10 characters");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_minPasswordComplexityStricter_pin() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_SOMETHING);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+                /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+                /* userEnteredPassword= */ "",
+                "PIN must be at least 8 digits");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_minPasswordComplexityStricter_password() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_SOMETHING);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "",
+                "Must contain at least 1 letter",
+                "Must be at least 4 characters");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_dpmRestrictionsStricter_password() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHANUMERIC);
+        mShadowDpm.setPasswordMinimumLength(9);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "",
+                "Must contain at least 1 letter",
+                "Must contain at least 1 numerical digit",
+                "Must be at least 9 characters");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_dpmLengthLonger_pin() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC);
+        mShadowDpm.setPasswordMinimumLength(11);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
+                /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+                /* userEnteredPassword= */ "",
+                "PIN must be at least 11 digits");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_dpmQualityComplex() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_COMPLEX);
+        mShadowDpm.setPasswordMinimumSymbols(2);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "",
+                "Must contain at least 2 special symbols",
+                "Must be at least 6 characters");
+    }
+
+    @Test
+    @Config(shadows = ShadowLockPatternUtils.class)
+    public void processAndValidatePasswordRequirements_numericComplexNoMinComplexity_pinRequested() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+                /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+                /* userEnteredPassword= */ "12345678",
+                "Ascending, descending, or repeated sequence of digits isn't allowed");
+    }
+
+    @Test
+    @Config(shadows = ShadowLockPatternUtils.class)
+    public void processAndValidatePasswordRequirements_numericComplexNoMinComplexity_passwordRequested() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "12345678",
+                "Ascending, descending, or repeated sequence of digits isn't allowed");
+    }
+
+    @Test
+    @Config(shadows = ShadowLockPatternUtils.class)
+    public void processAndValidatePasswordRequirements_numericComplexHighComplexity_pinRequested() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+                /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+                /* userEnteredPassword= */ "12345678",
+                "Ascending, descending, or repeated sequence of digits isn't allowed");
+    }
+
+    @Test
+    @Config(shadows = ShadowLockPatternUtils.class)
+    public void processAndValidatePasswordRequirements_numericHighComplexity_pinRequested() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+                /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+                /* userEnteredPassword= */ "12345678",
+                "Ascending, descending, or repeated sequence of digits isn't allowed");
+    }
+
+    @Test
+    @Config(shadows = ShadowLockPatternUtils.class)
+    public void processAndValidatePasswordRequirements_numericComplexLowComplexity_passwordRequested() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "12345678",
+                "Must contain at least 1 letter");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_empty() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "",
+                "Must contain at least 1 letter",
+                "Must be at least 6 characters");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_numeric() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "1",
+                "Must contain at least 1 letter",
+                "Must be at least 6 characters");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_alphabetic() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "b",
+                "Must be at least 6 characters");
+    }
+
+    @Test
+    public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_alphanumeric() {
+        mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+        assertPasswordValidationResult(
+                /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+                /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+                /* userEnteredPassword= */ "b1",
+                "Must be at least 6 characters");
+    }
+
+    @Test
     public void assertThat_chooseLockIconChanged_WhenFingerprintExtraSet() {
         ShadowDrawable drawable = setActivityAndGetIconDrawable(true);
         assertThat(drawable.getCreatedFromResId()).isEqualTo(R.drawable.ic_fingerprint_header);
@@ -132,4 +357,18 @@
         ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(passwordActivity);
         return Shadows.shadowOf(((GlifLayout) fragment.getView()).getIcon());
     }
+
+    private void assertPasswordValidationResult(@PasswordComplexity int minComplexity,
+            int passwordType, String userEnteredPassword, String... expectedValidationResult) {
+        Intent intent = new Intent();
+        intent.putExtra(CONFIRM_CREDENTIALS, false);
+        intent.putExtra(PASSWORD_TYPE_KEY, passwordType);
+        intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, minComplexity);
+        ChooseLockPassword activity = buildChooseLockPasswordActivity(intent);
+        ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
+        int validateResult = fragment.validatePassword(userEnteredPassword);
+        String[] messages = fragment.convertErrorCodeToMessages(validateResult);
+
+        assertThat(messages).asList().containsExactly((Object[]) expectedValidationResult);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/password/PasswordUtilsTest.java b/tests/robotests/src/com/android/settings/password/PasswordUtilsTest.java
new file mode 100644
index 0000000..845d346
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/password/PasswordUtilsTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 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.settings.password;
+
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.android.settings.password.PasswordUtils.getCallingAppLabel;
+import static com.android.settings.password.PasswordUtils.isCallingAppPermitted;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.settings.testutils.shadow.ShadowActivityManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowActivityManager.class})
+public class PasswordUtilsTest {
+
+    private static final String PACKAGE_NAME = "com.android.app";
+    private static final String PERMISSION = "com.testing.permission";
+    private static final int UID = 1234;
+
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private ApplicationInfo mApplicationInfo;
+    @Mock
+    private IActivityManager mActivityService;
+    @Mock
+    private IBinder mActivityToken;
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        ShadowActivityManager.setService(mActivityService);
+    }
+
+    @Test
+    public void getCallingAppLabel_activityServiceThrowsRemoteException_returnsNull()
+            throws Exception {
+        when(mActivityService.getLaunchedFromPackage(mActivityToken))
+                .thenThrow(new RemoteException());
+
+        assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
+    }
+
+    @Test
+    public void getCallingAppLabel_activityServiceReturnsSettingsApp_returnsNull()
+            throws Exception {
+        when(mActivityService.getLaunchedFromPackage(mActivityToken))
+                .thenReturn("com.android.settings");
+
+        assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
+    }
+
+    @Test
+    public void getCallingAppLabel_packageManagerThrowsNameNotFound_returnsNull() throws Exception {
+        when(mActivityService.getLaunchedFromPackage(mActivityToken))
+                .thenReturn(PACKAGE_NAME);
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenThrow(new NameNotFoundException());
+
+        assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
+    }
+
+    @Test
+    public void getCallingAppLabel_returnsLabel() throws Exception {
+        when(mActivityService.getLaunchedFromPackage(mActivityToken))
+                .thenReturn(PACKAGE_NAME);
+        when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(mApplicationInfo);
+        when(mApplicationInfo.loadLabel(mPackageManager)).thenReturn("label");
+
+        assertThat(getCallingAppLabel(mContext, mActivityToken)).isEqualTo("label");
+    }
+
+    @Test
+    public void isCallingAppPermitted_permissionGranted_returnsTrue() throws Exception {
+        when(mActivityService.getLaunchedFromUid(mActivityToken)).thenReturn(UID);
+        when(mContext.checkPermission(PERMISSION, -1, UID)).thenReturn(PERMISSION_GRANTED);
+
+        assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isTrue();
+    }
+
+    @Test
+    public void isCallingAppPermitted_permissionDenied_returnsFalse() throws Exception {
+        when(mActivityService.getLaunchedFromUid(mActivityToken)).thenReturn(UID);
+        when(mContext.checkPermission(PERMISSION, -1, UID)).thenReturn(PERMISSION_DENIED);
+
+        assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isFalse();
+    }
+
+    @Test
+    public void isCallingAppPermitted_throwsRemoteException_returnsFalse() throws Exception {
+        when(mActivityService.getLaunchedFromUid(mActivityToken)).thenThrow(new RemoteException());
+
+        assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
index 99738e7..d1b2b74 100644
--- a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
@@ -16,6 +16,16 @@
 
 package com.android.settings.password;
 
+import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.ComponentName;
@@ -23,6 +33,8 @@
 import android.os.Bundle;
 import android.provider.Settings;
 
+import com.android.settings.testutils.shadow.ShadowPasswordUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -31,11 +43,14 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowActivity;
 
 @RunWith(RobolectricTestRunner.class)
 public class SetNewPasswordActivityTest {
 
+    private static final String APP_LABEL = "label";
+
     private int mProvisioned;
 
     @Before
@@ -48,6 +63,7 @@
     public void tearDown() {
         Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, mProvisioned);
+        ShadowPasswordUtils.reset();
     }
 
     @Test
@@ -77,4 +93,106 @@
         assertThat(intent.getComponent())
                 .isEqualTo(new ComponentName(activity, SetupChooseLockGeneric.class));
     }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void testLaunchChooseLock_setNewPasswordExtraWithoutPermission() {
+        ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+        Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 1);
+
+        Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+        intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+        SetNewPasswordActivity activity =
+                Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+        assertThat(shadowActivity.getNextStartedActivityForResult()).isNull();
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void testLaunchChooseLock_setNewPasswordExtraWithPermission() {
+        ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+        ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+        Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 1);
+
+        Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+        intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+        SetNewPasswordActivity activity =
+                Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+        Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
+        assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
+        assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
+                .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+        assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void testLaunchChooseLock_setNewPasswordExtraInvalidValue() {
+        ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+        ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+        Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 1);
+
+        Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+        intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, -1);
+        SetNewPasswordActivity activity =
+                Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+        Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
+        assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+        assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void testLaunchChooseLock_setNewPasswordExtraNoneComplexity() {
+        ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+        ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+        Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 1);
+
+        Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+        intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
+        SetNewPasswordActivity activity =
+                Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+        Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
+        assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+        assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void testLaunchChooseLock_setNewParentProfilePasswordExtraWithPermission() {
+        ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+        ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+        Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 1);
+
+        Intent intent = new Intent(ACTION_SET_NEW_PARENT_PROFILE_PASSWORD);
+        intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+        SetNewPasswordActivity activity =
+                Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+        Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
+        assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PARENT_PROFILE_PASSWORD);
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
+        assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+        assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
new file mode 100644
index 0000000..63bdc38
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 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.settings.password;
+
+import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Intent;
+
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
+import com.android.settings.testutils.shadow.ShadowPasswordUtils;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settings.testutils.shadow.ShadowUtils;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowActivity;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+        ShadowUserManager.class,
+        ShadowUtils.class,
+        ShadowLockPatternUtils.class,
+})
+public class SetupChooseLockGenericTest {
+
+    @After
+    public void tearDown() {
+        ShadowPasswordUtils.reset();
+    }
+
+    @Test
+    public void setupChooseLockGenericPasswordComplexityExtraWithoutPermission() {
+        Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
+        intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+        SetupChooseLockGeneric activity =
+                Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+        assertThat(shadowActivity.isFinishing()).isTrue();
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void setupChooseLockGenericPasswordComplexityExtraWithPermission() {
+        ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+
+        Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
+        intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+        SetupChooseLockGeneric activity =
+                Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+        assertThat(shadowActivity.isFinishing()).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
index 38d658c..76bdaef 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
@@ -17,6 +17,7 @@
 package com.android.settings.testutils.shadow;
 
 import android.app.ActivityManager;
+import android.app.IActivityManager;
 
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
@@ -24,6 +25,7 @@
 @Implements(ActivityManager.class)
 public class ShadowActivityManager {
     private static int sCurrentUserId = 0;
+    private static IActivityManager sService = null;
 
     @Implementation
     protected static int getCurrentUser() {
@@ -33,4 +35,13 @@
     public static void setCurrentUser(int userId) {
         sCurrentUserId = userId;
     }
+
+    @Implementation
+    public static IActivityManager getService() {
+        return sService;
+    }
+
+    public static void setService(IActivityManager service) {
+        sService = service;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
index 6d2dbef..ca75916 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
@@ -1,5 +1,7 @@
 package com.android.settings.testutils.shadow;
 
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -23,6 +25,10 @@
     private boolean mIsAdminActiveAsUser = false;
     private ComponentName mDeviceOwnerComponentName;
     private int mDeviceOwnerUserId = -1;
+    private int mPasswordMinQuality = PASSWORD_QUALITY_UNSPECIFIED;
+    private int mPasswordMaxLength = 16;
+    private int mPasswordMinLength = 0;
+    private int mPasswordMinSymbols = 0;
 
     public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
         mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
@@ -70,6 +76,42 @@
         mDeviceOwnerComponentName = admin;
     }
 
+    @Implementation
+    public int getPasswordQuality(ComponentName admin, int userHandle) {
+        return mPasswordMinQuality;
+    }
+
+    public void setPasswordQuality(int quality) {
+        mPasswordMinQuality = quality;
+    }
+
+    @Implementation
+    public int getPasswordMinimumLength(ComponentName admin, int userHandle) {
+        return mPasswordMinLength;
+    }
+
+    public void setPasswordMinimumLength(int length) {
+        mPasswordMinLength = length;
+    }
+
+    @Implementation
+    public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) {
+        return mPasswordMinSymbols;
+    }
+
+    public void setPasswordMinimumSymbols(int numOfSymbols) {
+        mPasswordMinSymbols = numOfSymbols;
+    }
+
+    @Implementation
+    public int getPasswordMaximumLength(int quality) {
+        return mPasswordMaxLength;
+    }
+
+    public void setPasswordMaximumLength(int length) {
+        mPasswordMaxLength = length;
+    }
+
     public static ShadowDevicePolicyManager getShadow() {
         return (ShadowDevicePolicyManager) Shadow.extract(
                 RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
index 663ab91..7ce098d 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
@@ -59,4 +59,14 @@
     public static void setDeviceEncryptionEnabled(boolean deviceEncryptionEnabled) {
         sDeviceEncryptionEnabled = deviceEncryptionEnabled;
     }
+
+    @Implementation
+    protected byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
+        return null;
+    }
+
+    @Implementation
+    protected boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
+        return false;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPasswordUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPasswordUtils.java
new file mode 100644
index 0000000..6a5c4ae
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPasswordUtils.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 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.settings.testutils.shadow;
+
+import android.content.Context;
+import android.os.IBinder;
+
+import com.android.settings.password.PasswordUtils;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+@Implements(PasswordUtils.class)
+public class ShadowPasswordUtils {
+
+    private static String sCallingAppLabel;
+    private static Set<String> sGrantedPermissions;
+
+    public static void reset() {
+        sCallingAppLabel = null;
+        sGrantedPermissions = null;
+    }
+
+    @Implementation
+    protected static boolean isCallingAppPermitted(Context context, IBinder activityToken,
+            String permission) {
+        if (sGrantedPermissions == null) {
+            return false;
+        }
+        return sGrantedPermissions.contains(permission);
+    }
+
+    public static void addGrantedPermission(String... permissions) {
+        if (sGrantedPermissions == null) {
+            sGrantedPermissions = new HashSet<>();
+        }
+        sGrantedPermissions.addAll(Arrays.asList(permissions));
+    }
+
+    @Implementation
+    protected static String getCallingAppLabel(Context context, IBinder activityToken) {
+        return sCallingAppLabel;
+    }
+
+    public static void setCallingAppLabel(String label) {
+        sCallingAppLabel = label;
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
index ae352cc..dd99e55 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
@@ -139,4 +139,11 @@
 
         verify(mResolver).notifyChange(WIFI_SLICE_URI, null);
     }
+
+    @Test
+    public void onConnectedChanged_shouldNotifyChange() {
+        mWifiScanWorker.onConnectedChanged();
+
+        verify(mResolver).notifyChange(WIFI_SLICE_URI, null);
+    }
 }