Skip authentication if device was unlocked recently

- Sync the same behavior from SystemUI to Settings

Bug: 365611488
Flag: EXEMPT bugfix
Test: Manual testing
atest -c WifiNetworkDetailsFragmentTest \
         WifiDetailPreferenceController2Test \
         WifiTetherSSIDPreferenceControllerTest \
         com.android.settings.wifi.dpp.WifiDppUtilsTest
atest -c com.android.settings.spa.wifi.dpp.WifiDppUtilsTest

Change-Id: Ie3e8374b1fdbbc61e9e5bbf0f5162b18ba1452f3
This commit is contained in:
Weng Su
2024-12-13 08:44:05 +08:00
parent 626017d196
commit e5d19b38cb
6 changed files with 204 additions and 45 deletions

View File

@@ -57,7 +57,8 @@ public class AddDevicePreferenceController2 extends BasePreferenceController {
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (KEY_ADD_DEVICE.equals(preference.getKey())) {
WifiDppUtils.showLockScreen(mContext, () -> launchWifiDppConfiguratorQrCodeScanner());
WifiDppUtils.showLockScreenForWifiSharing(mContext,
() -> launchWifiDppConfiguratorQrCodeScanner());
return true; /* click is handled */
}

View File

@@ -980,7 +980,8 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle
* Share the wifi network with QR code.
*/
private void shareNetwork() {
WifiDppUtils.showLockScreen(mContext, () -> launchWifiDppConfiguratorActivity());
WifiDppUtils.showLockScreenForWifiSharing(mContext,
() -> launchWifiDppConfiguratorActivity());
}
/**

View File

@@ -16,6 +16,8 @@
package com.android.settings.wifi.dpp;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +35,9 @@ import android.os.Vibrator;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
@@ -58,6 +63,8 @@ import javax.crypto.SecretKey;
* @see WifiQrCode
*/
public class WifiDppUtils {
private static final String TAG = "WifiDppUtils";
/**
* The fragment tag specified to FragmentManager for container activities to manage fragments.
*/
@@ -109,7 +116,15 @@ public class WifiDppUtils {
private static final Duration VIBRATE_DURATION_QR_CODE_RECOGNITION = Duration.ofMillis(3);
private static final String AES_CBC_PKCS7_PADDING = "AES/CBC/PKCS7Padding";
/**
* Parameters to check whether the device has been locked recently
*/
@VisibleForTesting
public static final String AES_CBC_PKCS7_PADDING = "AES/CBC/PKCS7Padding";
@VisibleForTesting
public static final String WIFI_SHARING_KEY_ALIAS = "wifi_sharing_auth_key";
@VisibleForTesting
public static final int WIFI_SHARING_MAX_UNLOCK_SECONDS = 60;
/**
* Returns whether the device support WiFi DPP.
@@ -426,51 +441,75 @@ public class WifiDppUtils {
* Shows authentication screen to confirm credentials (pin, pattern or password) for the current
* user of the device.
*
* @param context The {@code Context} used to get {@code KeyguardManager} service
* @param context The {@code Context} used to get {@code KeyguardManager} service
* @param successRunnable The {@code Runnable} which will be executed if the user does not setup
* device security or if lock screen is unlocked
*/
public static void showLockScreen(Context context, Runnable successRunnable) {
final KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(
Context.KEYGUARD_SERVICE);
if (keyguardManager.isKeyguardSecure()) {
final BiometricPrompt.AuthenticationCallback authenticationCallback =
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(
BiometricPrompt.AuthenticationResult result) {
successRunnable.run();
}
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
//Do nothing
}
};
final int userId = UserHandle.myUserId();
final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(context)
.setTitle(context.getText(R.string.wifi_dpp_lockscreen_title));
if (keyguardManager.isDeviceSecure()) {
builder.setDeviceCredentialAllowed(true);
builder.setTextForDeviceCredential(
null /* title */,
Utils.getConfirmCredentialStringForUser(
context, userId, Utils.getCredentialType(context, userId)),
null /* description */);
}
final BiometricPrompt bp = builder.build();
final Handler handler = new Handler(Looper.getMainLooper());
bp.authenticate(new CancellationSignal(),
runnable -> handler.post(runnable),
authenticationCallback);
} else {
public static void showLockScreen(@NonNull Context context, @NonNull Runnable successRunnable) {
KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
if (keyguardManager == null || !keyguardManager.isKeyguardSecure()) {
successRunnable.run();
return;
}
showLockScreen(context, successRunnable, keyguardManager);
}
/**
* Shows authentication screen to confirm credentials (pin, pattern or password) for the
* current user of the device. But if the device has been unlocked recently, the
* authentication screen will be skipped.
*
* @param context The {@code Context} used to get {@code KeyguardManager} service
* @param successRunnable The {@code Runnable} which will be executed if the user does not setup
* device security or if lock screen is unlocked
*/
public static void showLockScreenForWifiSharing(@NonNull Context context,
@NonNull Runnable successRunnable) {
KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
if (keyguardManager == null || !keyguardManager.isKeyguardSecure()) {
successRunnable.run();
return;
}
if (isUnlockedWithinSeconds(WIFI_SHARING_KEY_ALIAS, WIFI_SHARING_MAX_UNLOCK_SECONDS)) {
Log.d(TAG, "Bypassing the lock screen because the device was unlocked recently.");
successRunnable.run();
return;
}
showLockScreen(context, successRunnable, keyguardManager);
}
@SuppressLint("MissingPermission")
private static void showLockScreen(@NonNull Context context, @NonNull Runnable successRunnable,
@NonNull KeyguardManager keyguardManager) {
BiometricPrompt.AuthenticationCallback authenticationCallback =
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(
BiometricPrompt.AuthenticationResult result) {
successRunnable.run();
}
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
//Do nothing
}
};
int userId = UserHandle.myUserId();
BiometricPrompt.Builder builder = new BiometricPrompt.Builder(context)
.setTitle(context.getText(R.string.wifi_dpp_lockscreen_title));
if (keyguardManager.isDeviceSecure()) {
builder.setDeviceCredentialAllowed(true);
builder.setTextForDeviceCredential(
null /* title */,
Utils.getConfirmCredentialStringForUser(
context, userId, Utils.getCredentialType(context, userId)),
null /* description */);
}
BiometricPrompt bp = builder.build();
Handler handler = new Handler(Looper.getMainLooper());
bp.authenticate(new CancellationSignal(),
runnable -> handler.post(runnable),
authenticationCallback);
}
/**

View File

@@ -123,7 +123,7 @@ public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreference
}
private void shareHotspotNetwork(Intent intent) {
WifiDppUtils.showLockScreen(mContext, () -> {
WifiDppUtils.showLockScreenForWifiSharing(mContext, () -> {
mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_SETTINGS_SHARE_WIFI_HOTSPOT_QR_CODE,
SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR,