Skip authentication in Wifi sharing if the device is unlocked recently

BUG: 311168955
Test: atest com.android.settings.wifi.dpp.WifiDppConfiguratorAuthActivityTest
Change-Id: I59674788e04d843541e8fcc3f3305ba295e8d8b1
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivity.java
index aa77dc1..010607f 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorAuthActivity.java
@@ -37,6 +37,8 @@
  * Sharing a Wi-Fi network by QR code after unlocking. Used by {@code InternetDialog} in QS.
  */
 public class WifiDppConfiguratorAuthActivity extends InstrumentedActivity {
+    private static final String WIFI_SHARING_KEY_ALIAS = "wifi_sharing_auth_key";
+    private static final int MAX_UNLOCK_SECONDS = 60;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -46,7 +48,9 @@
         Intent authIntent = getSystemService(KeyguardManager.class)
                 .createConfirmDeviceCredentialIntent(
                         getText(R.string.wifi_dpp_lockscreen_title), null, getUserId());
-        if (authIntent == null) {
+        if (authIntent == null
+                || WifiDppUtils.isUnlockedWithinSeconds(
+                        WIFI_SHARING_KEY_ALIAS, MAX_UNLOCK_SECONDS)) {
             startQrCodeActivity();
             finish();
         } else {
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 83a1571..23a6a54 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -30,6 +30,8 @@
 import android.os.UserHandle;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
 import android.text.TextUtils;
 
 import com.android.settings.R;
@@ -37,9 +39,19 @@
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.wifitrackerlib.WifiEntry;
 
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
 import java.time.Duration;
 import java.util.List;
 
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
 /**
  * Here are the items shared by both WifiDppConfiguratorActivity & WifiDppEnrolleeActivity
  *
@@ -97,6 +109,8 @@
 
     private static final Duration VIBRATE_DURATION_QR_CODE_RECOGNITION = Duration.ofMillis(3);
 
+    private static final String AES_CBC_PKCS7_PADDING = "AES/CBC/PKCS7Padding";
+
     /**
      * Returns whether the device support WiFi DPP.
      */
@@ -367,6 +381,48 @@
     }
 
     /**
+     * Checks whether the device is unlocked recently.
+     *
+     * @param keyStoreAlias key
+     * @param seconds how many seconds since the device is unlocked
+     * @return whether the device is unlocked within the time
+     */
+    public static boolean isUnlockedWithinSeconds(String keyStoreAlias, int seconds) {
+        try {
+            Cipher cipher = Cipher.getInstance(AES_CBC_PKCS7_PADDING);
+            cipher.init(Cipher.ENCRYPT_MODE, generateSecretKey(keyStoreAlias, seconds));
+            cipher.doFinal();
+            return true;
+        } catch (NoSuchPaddingException
+                 | IllegalBlockSizeException
+                 | NoSuchAlgorithmException
+                 | BadPaddingException
+                 | InvalidKeyException e) {
+            return false;
+        }
+    }
+
+    private static SecretKey generateSecretKey(String keyStoreAlias, int seconds) {
+        KeyGenParameterSpec spec = new KeyGenParameterSpec
+                .Builder(keyStoreAlias, KeyProperties.PURPOSE_ENCRYPT)
+                .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+                .setUserAuthenticationRequired(true)
+                .setUserAuthenticationParameters(
+                        seconds,
+                        KeyProperties.AUTH_DEVICE_CREDENTIAL | KeyProperties.AUTH_BIOMETRIC_STRONG)
+                .build();
+        try {
+            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
+            keyGenerator.init(spec);
+            return keyGenerator.generateKey();
+        } catch (NoSuchAlgorithmException
+                 | InvalidAlgorithmParameterException e) {
+            return null;
+        }
+    }
+
+    /**
      * Shows authentication screen to confirm credentials (pin, pattern or password) for the current
      * user of the device.
      *