Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 887d5de0 authored by Md Shahadat Hossain Shahin's avatar Md Shahadat Hossain Shahin Committed by Android (Google) Code Review
Browse files

Merge "Allow overriding default visibility for sensitive inputs" into main

parents 30e5c9e3 ce7efc29
Loading
Loading
Loading
Loading
+12 −35
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static android.security.Flags.shouldTrustManagerListenForPrimaryAuth;

import static com.android.internal.widget.flags.Flags.hideLastCharWithPhysicalInput;
import static com.android.internal.widget.flags.Flags.useDefaultVisibilityForSensitiveInputs;

import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -42,7 +42,6 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.input.InputManagerGlobal;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
@@ -60,7 +59,6 @@ import android.util.Log;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.view.InputDevice;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -1065,18 +1063,17 @@ public class LockPatternUtils {
        return type == CREDENTIAL_TYPE_PATTERN;
    }

    private boolean hasActivePointerDeviceAttached() {
        return !getEnabledNonTouchInputDevices(InputDevice.SOURCE_CLASS_POINTER).isEmpty();
    }

    /**
     * @return Whether the visible pattern is enabled.
     */
    @UnsupportedAppUsage
    public boolean isVisiblePatternEnabled(int userId) {
        boolean defaultValue = true;
        if (hideLastCharWithPhysicalInput()) {
            defaultValue = !hasActivePointerDeviceAttached();
        if (useDefaultVisibilityForSensitiveInputs()) {
            defaultValue =
                    mContext.getResources()
                            .getBoolean(
                                    com.android.internal.R.bool.config_lockPatternVisibleDefault);
        }
        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, defaultValue, userId);
    }
@@ -1092,37 +1089,17 @@ public class LockPatternUtils {
        return getString(Settings.Secure.LOCK_PATTERN_VISIBLE, userId) != null;
    }

    private List<InputDevice> getEnabledNonTouchInputDevices(int source) {
        final InputManagerGlobal inputManager = InputManagerGlobal.getInstance();
        final int[] inputIds = inputManager.getInputDeviceIds();
        List<InputDevice> matchingDevices = new ArrayList<InputDevice>();
        for (final int deviceId : inputIds) {
            final InputDevice inputDevice = inputManager.getInputDevice(deviceId);
            if (!inputDevice.isEnabled()) continue;
            if (inputDevice.supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) continue;
            if (inputDevice.isVirtual()) continue;
            if (!inputDevice.supportsSource(source)) continue;
            matchingDevices.add(inputDevice);
        }
        return matchingDevices;
    }

    private boolean hasPhysicalKeyboardActive() {
        final List<InputDevice> keyboards =
                getEnabledNonTouchInputDevices(InputDevice.SOURCE_KEYBOARD);
        for (final InputDevice keyboard : keyboards) {
            if (keyboard.isFullKeyboard()) return true;
        }
        return false;
    }

    /**
     * @return Whether enhanced pin privacy is enabled.
     */
    public boolean isPinEnhancedPrivacyEnabled(int userId) {
        boolean defaultValue = false;
        if (hideLastCharWithPhysicalInput()) {
            defaultValue = hasPhysicalKeyboardActive();
        if (useDefaultVisibilityForSensitiveInputs()) {
            defaultValue =
                    mContext.getResources()
                            .getBoolean(
                                    com.android.internal.R.bool
                                            .config_lockPinEnhancedPrivacyDefault);
        }
        return getBoolean(LOCK_PIN_ENHANCED_PRIVACY, defaultValue, userId);
    }
+10 −0
Original line number Diff line number Diff line
@@ -14,3 +14,13 @@ flag {
    description: "Feature flag for changing the priority of the check credential task"
    bug: "407716215"
}

flag {
    name: "use_default_visibility_for_sensitive_inputs"
    namespace: "input"
    description: "Allows setting default value for visibility of sensitive inputs (passowrd, pin and pattern)."
    bug: "339270220"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -1537,6 +1537,17 @@
         wrong guesses, improving usability. -->
    <bool name="config_softwareLskfRateLimiterEnforcing">false</bool>

    <!-- Default value of the setting that controls whether animations should be disabled while
         entering the PIN on the lockscreen.
         False means animations should be enabled by default.
         True means animations should be disabled by default. -->
    <bool name="config_lockPinEnhancedPrivacyDefault">false</bool>

    <!-- Default value for the setting that controls whether lock pattern is visible as user enters.
         True means the pattern should be visible by default.
         False means the pattern should not be visible by default. -->
    <bool name="config_lockPatternVisibleDefault">true</bool>

    <!-- Control the behavior when the user long presses the home button.
            0 - Nothing
            1 - Launch all apps intent
+3 −0
Original line number Diff line number Diff line
@@ -4196,6 +4196,9 @@
  <java-symbol type="bool" name="config_disableWeaverOnUnsecuredUsers" />
  <java-symbol type="bool" name="config_softwareLskfRateLimiterEnforcing" />

  <java-symbol type="bool" name="config_lockPinEnhancedPrivacyDefault" />
  <java-symbol type="bool" name="config_lockPatternVisibleDefault" />

  <!-- ETWS primary messages -->
  <java-symbol type="string" name="etws_primary_default_message_earthquake" />
  <java-symbol type="string" name="etws_primary_default_message_tsunami" />
+40 −130
Original line number Diff line number Diff line
@@ -47,8 +47,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManagerGlobal;
import android.content.res.Resources;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -60,7 +59,6 @@ import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.ravenwood.RavenwoodRule;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.view.InputDevice;

import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -95,6 +93,8 @@ public class LockPatternUtilsTest {

    private LockPatternUtils mLockPatternUtils;

    private Resources mResources;

    private void configureTest(boolean isSecure, boolean isDemoUser, int deviceDemoMode)
            throws Exception {
        mLockSettings = mock(ILockSettings.class);
@@ -458,155 +458,65 @@ public class LockPatternUtilsTest {
        };
    }

    private InputManagerGlobal.TestSession configureExternalHardwareTest(InputDevice[] devices)
            throws RemoteException {
        final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext());
    private void configureSensitiveInputVisibilityTest() throws RemoteException {
        final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
        final ILockSettings ils = mock(ILockSettings.class);
        when(ils.getBoolean(anyString(), anyBoolean(), anyInt())).thenThrow(RemoteException.class);
        mLockPatternUtils = new LockPatternUtils(context, ils);

        IInputManager inputManagerMock = mock(IInputManager.class);

        int[] deviceIds = new int[devices.length];

        for (int i = 0; i < devices.length; i++) {
            when(inputManagerMock.getInputDevice(i)).thenReturn(devices[i]);
        }

        when(inputManagerMock.getInputDeviceIds()).thenReturn(deviceIds);
        InputManagerGlobal.TestSession session =
                InputManagerGlobal.createTestSession(inputManagerMock);

        return session;
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isPinEnhancedPrivacyEnabled_noDevicesAttached() throws RemoteException {
        InputManagerGlobal.TestSession session = configureExternalHardwareTest(new InputDevice[0]);
        assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
        session.close();
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isPinEnhancedPrivacyEnabled_noEnabledDeviceAttached() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder.setEnabled(false);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
        assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
        session.close();
        mResources = spy(context.getResources());
        when(context.getResources()).thenReturn(mResources);
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isPinEnhancedPrivacyEnabled_withoutHwKeyboard() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder.setEnabled(true).setSources(InputDevice.SOURCE_TOUCHSCREEN);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
        assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
        session.close();
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isPinEnhancedPrivacyEnabled_withoutFullHwKeyboard() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder
                .setEnabled(true)
                .setSources(InputDevice.SOURCE_KEYBOARD)
                .setKeyboardType(InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
        assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
        session.close();
    }

    @Test
    @DisableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isPinEnhancedPrivacyEnabled_withHwKeyboardOldDefault() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder
                .setEnabled(true)
                .setSources(InputDevice.SOURCE_KEYBOARD)
                .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
        assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
        session.close();
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isPinEnhancedPrivacyEnabled_withHwKeyboard() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder
                .setEnabled(true)
                .setSources(InputDevice.SOURCE_KEYBOARD)
                .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
        assertTrue(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
        session.close();
    @EnableFlags(Flags.FLAG_USE_DEFAULT_VISIBILITY_FOR_SENSITIVE_INPUTS)
    public void isVisiblePatternEnabled_WhenConfigValueTrue() throws RemoteException {
        configureSensitiveInputVisibilityTest();
        when(mResources.getBoolean(com.android.internal.R.bool.config_lockPatternVisibleDefault))
                .thenReturn(true);
        assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isVisiblePatternEnabled_noDevices() throws RemoteException {
        InputManagerGlobal.TestSession session = configureExternalHardwareTest(new InputDevice[0]);
        assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
        session.close();
    @EnableFlags(Flags.FLAG_USE_DEFAULT_VISIBILITY_FOR_SENSITIVE_INPUTS)
    public void isVisiblePatternEnabled_WhenConfigValueFalse() throws RemoteException {
        configureSensitiveInputVisibilityTest();
        when(mResources.getBoolean(com.android.internal.R.bool.config_lockPatternVisibleDefault))
                .thenReturn(false);
        assertFalse(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isVisiblePatternEnabled_noEnabledDevices() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder.setEnabled(false);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
    @DisableFlags(Flags.FLAG_USE_DEFAULT_VISIBILITY_FOR_SENSITIVE_INPUTS)
    public void isVisiblePatternEnabled_OldDefault() throws RemoteException {
        configureSensitiveInputVisibilityTest();
        assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
        session.close();
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isVisiblePatternEnabled_noPointingDevices() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder
                .setEnabled(true)
                .setSources(InputDevice.SOURCE_TOUCHSCREEN);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
        assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
        session.close();
    @EnableFlags(Flags.FLAG_USE_DEFAULT_VISIBILITY_FOR_SENSITIVE_INPUTS)
    public void isPinEnhancedPrivacyEnabled_WhenConfigValueTrue() throws RemoteException {
        configureSensitiveInputVisibilityTest();
        when(mResources.getBoolean(
                        com.android.internal.R.bool.config_lockPinEnhancedPrivacyDefault))
                .thenReturn(true);
        assertTrue(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
    }

    @Test
    @EnableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isVisiblePatternEnabled_externalPointingDevice() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder
                .setEnabled(true)
                .setSources(InputDevice.SOURCE_CLASS_POINTER);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
        assertFalse(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
        session.close();
    @EnableFlags(Flags.FLAG_USE_DEFAULT_VISIBILITY_FOR_SENSITIVE_INPUTS)
    public void isPinEnhancedPrivacyEnabled_WhenConfigValueFalse() throws RemoteException {
        configureSensitiveInputVisibilityTest();
        when(mResources.getBoolean(
                        com.android.internal.R.bool.config_lockPinEnhancedPrivacyDefault))
                .thenReturn(false);
        assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
    }

    @Test
    @DisableFlags(Flags.FLAG_HIDE_LAST_CHAR_WITH_PHYSICAL_INPUT)
    public void isVisiblePatternEnabled_externalPointingDeviceOldDefault() throws RemoteException {
        InputDevice.Builder builder = new InputDevice.Builder();
        builder
                .setEnabled(true)
                .setSources(InputDevice.SOURCE_CLASS_POINTER);
        InputManagerGlobal.TestSession session =
                configureExternalHardwareTest(new InputDevice[]{builder.build()});
        assertTrue(mLockPatternUtils.isVisiblePatternEnabled(USER_ID));
        session.close();
    @DisableFlags(Flags.FLAG_USE_DEFAULT_VISIBILITY_FOR_SENSITIVE_INPUTS)
    public void isPinEnhancedPrivacyEnabled_OldDefault() throws RemoteException {
        configureSensitiveInputVisibilityTest();
        assertFalse(mLockPatternUtils.isPinEnhancedPrivacyEnabled(USER_ID));
    }
}