Snap for 9744320 from 17701cd976 to tm-qpr3-release

Change-Id: Ibf62a89f946fa7d1fc763057e7be67c6e7cb79f2
This commit is contained in:
Android Build Coastguard Worker
2023-03-14 23:25:08 +00:00
12 changed files with 254 additions and 19 deletions

View File

@@ -20,6 +20,7 @@
android:id="@+id/panel_container" android:id="@+id/panel_container"
android:layout_width="@dimen/settings_panel_width" android:layout_width="@dimen/settings_panel_width"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:background="@drawable/settings_panel_rounded_top_corner_background" > android:background="@drawable/settings_panel_rounded_top_corner_background" >

View File

@@ -4805,6 +4805,9 @@
<string name="lockpattern_settings_enable_summary">Must draw pattern to unlock screen</string> <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.--> <!-- 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> <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.--> <!-- 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> <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.--> <!-- Security & location settings screen, setting check box title. This setting controls whether tactile feedback will be produced when the user draws the pattern.-->

View File

@@ -229,6 +229,7 @@
<!-- Note that Dialog themes do not set list dividers --> <!-- Note that Dialog themes do not set list dividers -->
<style name="Theme.Panel" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog"> <style name="Theme.Panel" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog">
<item name="android:windowBackground">@null</item> <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:dividerHorizontal">@*android:drawable/list_divider_material</item>
<item name="android:windowNoTitle">true</item> <item name="android:windowNoTitle">true</item>
<item name="android:listDivider">@*android:drawable/list_divider_material</item> <item name="android:listDivider">@*android:drawable/list_divider_material</item>

View File

@@ -27,6 +27,12 @@
android:key="visiblepattern" android:key="visiblepattern"
android:title="@string/lockpattern_settings_enable_visible_pattern_title" /> 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 --> <!-- available in pin/pattern/password -->
<com.android.settings.display.TimeoutListPreference <com.android.settings.display.TimeoutListPreference
android:key="lock_after_timeout" android:key="lock_after_timeout"

View File

@@ -29,12 +29,15 @@ import android.view.WindowManager;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
/** /**
@@ -144,9 +147,33 @@ public class SettingsPanelActivity extends FragmentActivity {
window.setGravity(Gravity.BOTTOM); window.setGravity(Gravity.BOTTOM);
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT); WindowManager.LayoutParams.WRAP_CONTENT);
setupNavigationBar();
mPanelFragment = new PanelFragment(); mPanelFragment = new PanelFragment();
mPanelFragment.setArguments(new Bundle(mBundle)); mPanelFragment.setArguments(new Bundle(mBundle));
fragmentManager.beginTransaction().add(R.id.main_content, mPanelFragment).commit(); 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);
}
}
} }

View File

@@ -17,29 +17,22 @@
package com.android.settings.security.screenlock; package com.android.settings.security.screenlock;
import android.content.Context; import android.content.Context;
import android.os.UserHandle;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.notification.LockScreenNotificationPreferenceController; 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.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnResume; import com.android.settingslib.core.lifecycle.events.OnResume;
public class LockScreenPreferenceController extends BasePreferenceController implements public class LockScreenPreferenceController extends BasePreferenceController implements
LifecycleObserver, OnResume { LifecycleObserver, OnResume {
private static final int MY_USER_ID = UserHandle.myUserId();
private final LockPatternUtils mLockPatternUtils;
private Preference mPreference; private Preference mPreference;
public LockScreenPreferenceController(Context context, String key) { public LockScreenPreferenceController(Context context, String key) {
super(context, key); super(context, key);
mLockPatternUtils = FeatureFactory.getFactory(context)
.getSecurityFeatureProvider().getLockPatternUtils(context);
} }
@Override @Override

View File

@@ -16,7 +16,6 @@
package com.android.settings.security.screenlock; package com.android.settings.security.screenlock;
import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
import androidx.preference.Preference; import androidx.preference.Preference;
@@ -58,9 +57,8 @@ public class PatternVisiblePreferenceController extends AbstractPreferenceContro
} }
private boolean isPatternLock() { private boolean isPatternLock() {
return mLockPatternUtils.isSecure(mUserId) return mLockPatternUtils.getCredentialTypeForUser(mUserId)
&& mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId) == LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
== DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
} }
@Override @Override

View File

@@ -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)
}
}

View File

@@ -68,9 +68,12 @@ public class ScreenLockSettings extends DashboardFragment
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context, private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
DashboardFragment parent, LockPatternUtils lockPatternUtils) { DashboardFragment parent, LockPatternUtils lockPatternUtils) {
final List<AbstractPreferenceController> controllers = new ArrayList<>(); final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new PatternVisiblePreferenceController( controllers.add(new PatternVisiblePreferenceController(
context, MY_USER_ID, lockPatternUtils)); context, MY_USER_ID, lockPatternUtils));
controllers.add(new PinPrivacyPreferenceController(
context, MY_USER_ID, lockPatternUtils));
controllers.add(new PowerButtonInstantLockPreferenceController( controllers.add(new PowerButtonInstantLockPreferenceController(
context, MY_USER_ID, lockPatternUtils)); context, MY_USER_ID, lockPatternUtils));
controllers.add(new LockAfterTimeoutPreferenceController( controllers.add(new LockAfterTimeoutPreferenceController(

View File

@@ -16,11 +16,13 @@
package com.android.settings.panel; 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 android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@@ -30,15 +32,20 @@ import static org.mockito.Mockito.when;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Build; import android.os.Build;
import android.view.View;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -61,6 +68,9 @@ public class SettingsPanelActivityTest {
private PanelFragment mPanelFragment; private PanelFragment mPanelFragment;
@Mock @Mock
private FragmentManager mFragmentManager; private FragmentManager mFragmentManager;
@Mock
private FragmentTransaction mTransaction;
private int mOriginalUiMode;
@Before @Before
public void setUp() { public void setUp() {
@@ -76,6 +86,15 @@ public class SettingsPanelActivityTest {
mSettingsPanelActivity.mPanelFragment = mPanelFragment; mSettingsPanelActivity.mPanelFragment = mPanelFragment;
when(mFragmentManager.findFragmentById(R.id.main_content)).thenReturn(mPanelFragment); when(mFragmentManager.findFragmentById(R.id.main_content)).thenReturn(mPanelFragment);
when(mSettingsPanelActivity.getSupportFragmentManager()).thenReturn(mFragmentManager); 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 @Test
@@ -179,4 +198,24 @@ public class SettingsPanelActivityTest {
verify(mPanelFragment, never()).updatePanelWithAnimation(); 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();
}
} }

View File

@@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
import android.content.Context; import android.content.Context;
import androidx.preference.SwitchPreference; import androidx.preference.SwitchPreference;
@@ -52,24 +51,22 @@ public class PatternVisiblePreferenceControllerTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;
mController = mController =
new PatternVisiblePreferenceController(mContext, TEST_USER_ID, mLockPatternUtils); new PatternVisiblePreferenceController(mContext, TEST_USER_ID, mLockPatternUtils);
mPreference = new SwitchPreference(mContext); mPreference = new SwitchPreference(mContext);
} }
@Test @Test
public void isAvailable_lockSetToPattern_shouldReturnTrue() { public void isAvailable_lockSetToPattern_shouldReturnTrue() {
when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID))
when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) .thenReturn(LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
assertThat(mController.isAvailable()).isTrue(); assertThat(mController.isAvailable()).isTrue();
} }
@Test @Test
public void isAvailable_lockSetToPin_shouldReturnFalse() { public void isAvailable_lockSetToPin_shouldReturnFalse() {
when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID)).thenReturn(
when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) LockPatternUtils.CREDENTIAL_TYPE_PIN);
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
assertThat(mController.isAvailable()).isFalse(); assertThat(mController.isAvailable()).isFalse();
} }

View File

@@ -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();
}
}