Snap for 9744320 from 17701cd976 to tm-qpr3-release
Change-Id: Ibf62a89f946fa7d1fc763057e7be67c6e7cb79f2
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
android:id="@+id/panel_container"
|
||||
android:layout_width="@dimen/settings_panel_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/settings_panel_rounded_top_corner_background" >
|
||||
|
||||
|
||||
@@ -4805,6 +4805,9 @@
|
||||
<string name="lockpattern_settings_enable_summary">Must draw pattern to unlock screen</string>
|
||||
<!-- Security & location settings screen, setting check box title. This setting controls whether a visible green line is drawn as the users move their finger around while drawing the unlock pattern. If checked, this line is drawn. If unchecked, there is nothing drawn so the users do not reveal their pattern while they unlock the phone.-->
|
||||
<string name="lockpattern_settings_enable_visible_pattern_title">Make pattern visible</string>
|
||||
<!-- Security & location settings screen, setting check box title. This setting disables animations when entering the PIN.-->
|
||||
<string name="lockpattern_settings_enhanced_pin_privacy_title">Enhanced PIN privacy</string>
|
||||
<string name="lockpattern_settings_enhanced_pin_privacy_summary">Disable animations while entering the PIN</string>
|
||||
<!-- Security & location settings screen, setting check box title. This setting controls whether a visible green line is drawn as the users move their finger around while drawing the profile unlock pattern. If checked, this line is drawn. If unchecked, there is nothing drawn so the users do not reveal their pattern while they unlock the profile.-->
|
||||
<string name="lockpattern_settings_enable_visible_pattern_title_profile">Make profile pattern visible</string>
|
||||
<!-- Security & location settings screen, setting check box title. This setting controls whether tactile feedback will be produced when the user draws the pattern.-->
|
||||
|
||||
@@ -229,6 +229,7 @@
|
||||
<!-- Note that Dialog themes do not set list dividers -->
|
||||
<style name="Theme.Panel" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog">
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
<item name="android:dividerHorizontal">@*android:drawable/list_divider_material</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:listDivider">@*android:drawable/list_divider_material</item>
|
||||
|
||||
@@ -27,6 +27,12 @@
|
||||
android:key="visiblepattern"
|
||||
android:title="@string/lockpattern_settings_enable_visible_pattern_title" />
|
||||
|
||||
<!-- available in pin -->
|
||||
<SwitchPreference
|
||||
android:key="enhancedPinPrivacy"
|
||||
android:title="@string/lockpattern_settings_enhanced_pin_privacy_title"
|
||||
android:summary="@string/lockpattern_settings_enhanced_pin_privacy_summary" />
|
||||
|
||||
<!-- available in pin/pattern/password -->
|
||||
<com.android.settings.display.TimeoutListPreference
|
||||
android:key="lock_after_timeout"
|
||||
|
||||
@@ -29,12 +29,15 @@ import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
|
||||
|
||||
/**
|
||||
@@ -144,9 +147,33 @@ public class SettingsPanelActivity extends FragmentActivity {
|
||||
window.setGravity(Gravity.BOTTOM);
|
||||
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT);
|
||||
setupNavigationBar();
|
||||
mPanelFragment = new PanelFragment();
|
||||
mPanelFragment.setArguments(new Bundle(mBundle));
|
||||
fragmentManager.beginTransaction().add(R.id.main_content, mPanelFragment).commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust bottom edge and color.
|
||||
*/
|
||||
private void setupNavigationBar() {
|
||||
// Extend the panel all the way to the bottom of the screen, as opposed to sitting on top of
|
||||
// the navigation bar.
|
||||
ViewCompat.setOnApplyWindowInsetsListener(getWindow().getDecorView(),
|
||||
(v, windowInsets) -> {
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), 0);
|
||||
return windowInsets; // propagate down to panel layout root element
|
||||
});
|
||||
|
||||
// When using 3-button navigation in light mode, the system picks white navigation buttons
|
||||
// which are not sufficiently contrasted from the panel background.
|
||||
WindowInsetsControllerCompat windowInsetsController =
|
||||
ViewCompat.getWindowInsetsController(getWindow().getDecorView());
|
||||
|
||||
if (windowInsetsController != null) {
|
||||
boolean forceNavigationButtonsDark = !Utils.isNightMode(this);
|
||||
windowInsetsController.setAppearanceLightNavigationBars(forceNavigationButtonsDark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,29 +17,22 @@
|
||||
package com.android.settings.security.screenlock;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.notification.LockScreenNotificationPreferenceController;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
|
||||
public class LockScreenPreferenceController extends BasePreferenceController implements
|
||||
LifecycleObserver, OnResume {
|
||||
|
||||
private static final int MY_USER_ID = UserHandle.myUserId();
|
||||
private final LockPatternUtils mLockPatternUtils;
|
||||
private Preference mPreference;
|
||||
|
||||
public LockScreenPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
mLockPatternUtils = FeatureFactory.getFactory(context)
|
||||
.getSecurityFeatureProvider().getLockPatternUtils(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.settings.security.screenlock;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
@@ -58,9 +57,8 @@ public class PatternVisiblePreferenceController extends AbstractPreferenceContro
|
||||
}
|
||||
|
||||
private boolean isPatternLock() {
|
||||
return mLockPatternUtils.isSecure(mUserId)
|
||||
&& mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)
|
||||
== DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
|
||||
return mLockPatternUtils.getCredentialTypeForUser(mUserId)
|
||||
== LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.security.screenlock
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.TwoStatePreference
|
||||
import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.internal.widget.LockPatternUtils.*
|
||||
import com.android.settings.core.PreferenceControllerMixin
|
||||
import com.android.settingslib.core.AbstractPreferenceController
|
||||
|
||||
class PinPrivacyPreferenceController(
|
||||
context: Context,
|
||||
private val userId: Int,
|
||||
private val lockPatternUtils: LockPatternUtils
|
||||
) : AbstractPreferenceController(context), PreferenceControllerMixin,
|
||||
Preference.OnPreferenceChangeListener {
|
||||
|
||||
companion object {
|
||||
private const val PREF_KEY = "enhancedPinPrivacy"
|
||||
}
|
||||
|
||||
override fun isAvailable(): Boolean {
|
||||
val credentialType = lockPatternUtils.getCredentialTypeForUser(userId)
|
||||
return credentialType == CREDENTIAL_TYPE_PIN
|
||||
}
|
||||
|
||||
override fun getPreferenceKey(): String {
|
||||
return PREF_KEY
|
||||
}
|
||||
|
||||
override fun onPreferenceChange(preference: Preference?, value: Any?): Boolean {
|
||||
lockPatternUtils.setPinEnhancedPrivacyEnabled((value as Boolean), userId)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun updateState(preference: Preference) {
|
||||
(preference as TwoStatePreference).isChecked = getCurrentPreferenceState()
|
||||
}
|
||||
|
||||
private fun getCurrentPreferenceState(): Boolean {
|
||||
return lockPatternUtils.isPinEnhancedPrivacyEnabled(userId)
|
||||
}
|
||||
}
|
||||
@@ -68,9 +68,12 @@ public class ScreenLockSettings extends DashboardFragment
|
||||
|
||||
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
|
||||
DashboardFragment parent, LockPatternUtils lockPatternUtils) {
|
||||
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
controllers.add(new PatternVisiblePreferenceController(
|
||||
context, MY_USER_ID, lockPatternUtils));
|
||||
controllers.add(new PinPrivacyPreferenceController(
|
||||
context, MY_USER_ID, lockPatternUtils));
|
||||
controllers.add(new PowerButtonInstantLockPreferenceController(
|
||||
context, MY_USER_ID, lockPatternUtils));
|
||||
controllers.add(new LockAfterTimeoutPreferenceController(
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package com.android.settings.panel;
|
||||
|
||||
import static android.content.res.Configuration.UI_MODE_NIGHT_NO;
|
||||
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -30,15 +32,20 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -61,6 +68,9 @@ public class SettingsPanelActivityTest {
|
||||
private PanelFragment mPanelFragment;
|
||||
@Mock
|
||||
private FragmentManager mFragmentManager;
|
||||
@Mock
|
||||
private FragmentTransaction mTransaction;
|
||||
private int mOriginalUiMode;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -76,6 +86,15 @@ public class SettingsPanelActivityTest {
|
||||
mSettingsPanelActivity.mPanelFragment = mPanelFragment;
|
||||
when(mFragmentManager.findFragmentById(R.id.main_content)).thenReturn(mPanelFragment);
|
||||
when(mSettingsPanelActivity.getSupportFragmentManager()).thenReturn(mFragmentManager);
|
||||
mOriginalUiMode = mSettingsPanelActivity.getResources().getConfiguration().uiMode;
|
||||
when(mFragmentManager.beginTransaction()).thenReturn(mTransaction);
|
||||
when(mTransaction.add(anyInt(), any())).thenReturn(mTransaction);
|
||||
when(mTransaction.commit()).thenReturn(0); // don't care about return value
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mSettingsPanelActivity.getResources().getConfiguration().uiMode = mOriginalUiMode;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -179,4 +198,24 @@ public class SettingsPanelActivityTest {
|
||||
|
||||
verify(mPanelFragment, never()).updatePanelWithAnimation();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreated_isWindowBottomPaddingZero() {
|
||||
int paddingBottom = mSettingsPanelActivity.getWindow().getDecorView().getPaddingBottom();
|
||||
assertThat(paddingBottom).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notInNightMode_lightNavigationBarAppearance() {
|
||||
Configuration config = mSettingsPanelActivity.getResources().getConfiguration();
|
||||
config.uiMode = UI_MODE_NIGHT_NO;
|
||||
mSettingsPanelActivity.onConfigurationChanged(config); // forces creation
|
||||
|
||||
mSettingsPanelActivity.onNewIntent(mSettingsPanelActivity.getIntent());
|
||||
verify(mFragmentManager).beginTransaction();
|
||||
|
||||
View decorView = mSettingsPanelActivity.getWindow().getDecorView();
|
||||
WindowInsetsControllerCompat controller = ViewCompat.getWindowInsetsController(decorView);
|
||||
assertThat(controller.isAppearanceLightNavigationBars()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.SwitchPreference;
|
||||
@@ -52,24 +51,22 @@ public class PatternVisiblePreferenceControllerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController =
|
||||
new PatternVisiblePreferenceController(mContext, TEST_USER_ID, mLockPatternUtils);
|
||||
new PatternVisiblePreferenceController(mContext, TEST_USER_ID, mLockPatternUtils);
|
||||
mPreference = new SwitchPreference(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_lockSetToPattern_shouldReturnTrue() {
|
||||
when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true);
|
||||
when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID))
|
||||
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
||||
when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID))
|
||||
.thenReturn(LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
|
||||
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_lockSetToPin_shouldReturnFalse() {
|
||||
when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true);
|
||||
when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID))
|
||||
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||
when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID)).thenReturn(
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PIN);
|
||||
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.security.screenlock;
|
||||
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
|
||||
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;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PinPrivacyPreferenceControllerTest {
|
||||
|
||||
private static final int TEST_USER_ID = 0;
|
||||
|
||||
@Mock
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
private Context mContext;
|
||||
private PinPrivacyPreferenceController mController;
|
||||
private SwitchPreference mPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController =
|
||||
new PinPrivacyPreferenceController(mContext, TEST_USER_ID, mLockPatternUtils);
|
||||
mPreference = new SwitchPreference(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_lockSetToPin_shouldReturnTrue() {
|
||||
when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID)).thenReturn(
|
||||
CREDENTIAL_TYPE_PIN);
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_lockSetToPinOrPw_shouldReturnTrue() {
|
||||
when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID)).thenReturn(
|
||||
CREDENTIAL_TYPE_PASSWORD_OR_PIN);
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_lockSetToOther_shouldReturnFalse() {
|
||||
when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID)).thenReturn(
|
||||
CREDENTIAL_TYPE_PATTERN);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_shouldSetPref() {
|
||||
when(mLockPatternUtils.isPinEnhancedPrivacyEnabled(TEST_USER_ID)).thenReturn(true);
|
||||
mController.updateState(mPreference);
|
||||
assertThat(mPreference.isChecked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_shouldSetPref_false() {
|
||||
when(mLockPatternUtils.isPinEnhancedPrivacyEnabled(TEST_USER_ID)).thenReturn(false);
|
||||
mController.updateState(mPreference);
|
||||
assertThat(mPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChange_shouldUpdateLockPatternUtils() {
|
||||
mController.onPreferenceChange(mPreference, true);
|
||||
verify(mLockPatternUtils).setPinEnhancedPrivacyEnabled(true, TEST_USER_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPreferenceKey_returnsConst() {
|
||||
assertThat(mController.getPreferenceKey().equals("enhancedPinPrivacy")).isTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user