diff --git a/src/com/android/settings/dashboard/conditional/BatterySaverCondition.java b/src/com/android/settings/dashboard/conditional/BatterySaverCondition.java index f1962efa9cd..728154d5d6d 100644 --- a/src/com/android/settings/dashboard/conditional/BatterySaverCondition.java +++ b/src/com/android/settings/dashboard/conditional/BatterySaverCondition.java @@ -23,12 +23,20 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.core.SubSettingLauncher; import com.android.settings.fuelgauge.BatterySaverDrawable; +import com.android.settings.fuelgauge.BatterySaverReceiver; import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings; import com.android.settingslib.fuelgauge.BatterySaverUtils; -public class BatterySaverCondition extends Condition { +public class BatterySaverCondition extends Condition implements + BatterySaverReceiver.BatterySaverListener { + + private final BatterySaverReceiver mReceiver; + public BatterySaverCondition(ConditionManager manager) { super(manager); + + mReceiver = new BatterySaverReceiver(manager.getContext()); + mReceiver.setBatterySaverListener(this); } @Override @@ -54,7 +62,7 @@ public class BatterySaverCondition extends Condition { @Override public CharSequence[] getActions() { - return new CharSequence[] {mManager.getContext().getString(R.string.condition_turn_off)}; + return new CharSequence[]{mManager.getContext().getString(R.string.condition_turn_off)}; } @Override @@ -82,4 +90,25 @@ public class BatterySaverCondition extends Condition { public int getMetricsConstant() { return MetricsEvent.SETTINGS_CONDITION_BATTERY_SAVER; } + + @Override + public void onResume() { + mReceiver.setListening(true); + } + + @Override + public void onPause() { + mReceiver.setListening(false); + } + + @Override + public void onPowerSaveModeChanged() { + ConditionManager.get(mManager.getContext()).getCondition(BatterySaverCondition.class) + .refreshState(); + } + + @Override + public void onBatteryChanged(boolean pluggedIn) { + // do nothing + } } diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java index 7e302c4818b..6fb0df62123 100644 --- a/src/com/android/settings/datausage/BillingCyclePreference.java +++ b/src/com/android/settings/datausage/BillingCyclePreference.java @@ -88,7 +88,7 @@ public class BillingCyclePreference extends Preference implements TemplatePrefer return new SubSettingLauncher(getContext()) .setDestination(BillingCycleSettings.class.getName()) .setArguments(args) - .setTitle(getTitle()) + .setTitle(R.string.billing_cycle) .setSourceMetricsCategory(MetricsProto.MetricsEvent.VIEW_UNKNOWN) .toIntent(); } diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index 14f7d6bd6c4..e60b4e6d0e5 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -193,6 +193,7 @@ public class ChooseLockPassword extends SettingsActivity { private int mPasswordMinLengthToFulfillAllPolicies = 0; protected int mUserId; private boolean mHideDrawer = false; + private byte[] mPasswordHistoryHashFactor; /** * Password requirements that we need to verify. */ @@ -667,7 +668,8 @@ public class ChooseLockPassword extends SettingsActivity { } } // Is the password recently used? - if (mLockPatternUtils.checkPasswordHistory(password, mUserId)) { + if (mLockPatternUtils.checkPasswordHistory(password, getPasswordHistoryHashFactor(), + mUserId)) { errorCode |= RECENTLY_USED; } } @@ -730,6 +732,18 @@ public class ChooseLockPassword extends SettingsActivity { return errorCode; } + /** + * Lazily compute and return the history hash factor of the current user (mUserId), used for + * password history check. + */ + private byte[] getPasswordHistoryHashFactor() { + if (mPasswordHistoryHashFactor == null) { + mPasswordHistoryHashFactor = mLockPatternUtils.getPasswordHistoryHashFactor( + mCurrentPassword, mUserId); + } + return mPasswordHistoryHashFactor; + } + public void handleNext() { if (mSaveAndFinishWorker != null) return; mChosenPassword = mPasswordEntry.getText().toString(); diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java index 28ad3f5f3d3..b2dafcc8df0 100644 --- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java +++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java @@ -134,6 +134,7 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mPreference = screen.findPreference(mPreferenceKey); + mPreference.setVisible(false); } @Override diff --git a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java index 2f21f1b0023..58ea7b7e1d1 100644 --- a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java +++ b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java @@ -47,7 +47,7 @@ public class HandsFreeProfileOutputPreferenceController extends if (!isOngoingCallStatus()) { // Without phone call, disable the switch entry. - preference.setEnabled(false); + mPreference.setVisible(false); preference.setSummary(mContext.getText(R.string.media_output_default_summary)); return; } @@ -67,12 +67,12 @@ public class HandsFreeProfileOutputPreferenceController extends final int numDevices = ArrayUtils.size(mConnectedDevices); if (numDevices == 0) { // No connected devices, disable switch entry. - preference.setEnabled(false); + mPreference.setVisible(false); preference.setSummary(mContext.getText(R.string.media_output_default_summary)); return; } - preference.setEnabled(true); + mPreference.setVisible(true); CharSequence[] mediaOutputs = new CharSequence[numDevices + 1]; CharSequence[] mediaValues = new CharSequence[numDevices + 1]; diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java index df07dc5fa68..dce19f171e2 100644 --- a/src/com/android/settings/sound/MediaOutputPreferenceController.java +++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java @@ -52,14 +52,14 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_REMOTE_SUBMIX)) { // In cast mode, disable switch entry. - preference.setEnabled(false); + mPreference.setVisible(false); preference.setSummary(mContext.getText(R.string.media_output_summary_unavailable)); return; } if (isOngoingCallStatus()) { // Ongoing call status, switch entry for media will be disabled. - preference.setEnabled(false); + mPreference.setVisible(false); preference.setSummary( mContext.getText(R.string.media_out_summary_ongoing_call_state)); return; @@ -79,12 +79,12 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro final int numDevices = ArrayUtils.size(mConnectedDevices); if (numDevices == 0) { // Disable switch entry if there is no connected devices. - preference.setEnabled(false); + mPreference.setVisible(false); preference.setSummary(mContext.getText(R.string.media_output_default_summary)); return; } - preference.setEnabled(true); + mPreference.setVisible(true); CharSequence[] mediaOutputs = new CharSequence[numDevices + 1]; CharSequence[] mediaValues = new CharSequence[numDevices + 1]; diff --git a/src/com/android/settings/widget/HotspotApBandSelectionPreference.java b/src/com/android/settings/widget/HotspotApBandSelectionPreference.java index 4f127eb9193..0a2405e4136 100644 --- a/src/com/android/settings/widget/HotspotApBandSelectionPreference.java +++ b/src/com/android/settings/widget/HotspotApBandSelectionPreference.java @@ -118,8 +118,8 @@ public class HotspotApBandSelectionPreference extends CustomDialogPreference imp SavedState myState = new SavedState(superState); myState.shouldRestore = getDialog() != null; - myState.enabled2G = mBox2G.isChecked(); - myState.enabled5G = mBox5G.isChecked(); + myState.enabled2G = mBox2G != null && mBox2G.isChecked(); + myState.enabled5G = mBox5G != null && mBox5G.isChecked(); return myState; } diff --git a/tests/robotests/src/com/android/settings/dashboard/conditional/BatterySaverConditionTest.java b/tests/robotests/src/com/android/settings/dashboard/conditional/BatterySaverConditionTest.java new file mode 100644 index 00000000000..84093c47c85 --- /dev/null +++ b/tests/robotests/src/com/android/settings/dashboard/conditional/BatterySaverConditionTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018 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.dashboard.conditional; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.IntentFilter; +import android.os.PowerManager; + +import com.android.settings.R; +import com.android.settings.fuelgauge.BatterySaverReceiver; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; +import org.robolectric.shadows.ShadowPowerManager; + +@RunWith(SettingsRobolectricTestRunner.class) +public class BatterySaverConditionTest { + @Mock + private ConditionManager mConditionManager; + + private ShadowPowerManager mPowerManager; + private Context mContext; + private BatterySaverCondition mCondition; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + mPowerManager = Shadows.shadowOf(mContext.getSystemService(PowerManager.class)); + when(mConditionManager.getContext()).thenReturn(mContext); + mCondition = spy(new BatterySaverCondition(mConditionManager)); + } + + @Test + public void verifyText() { + assertThat(mCondition.getTitle()).isEqualTo( + mContext.getText(R.string.condition_battery_title)); + assertThat(mCondition.getSummary()).isEqualTo( + mContext.getText(R.string.condition_battery_summary)); + assertThat(mCondition.getActions()[0]).isEqualTo( + mContext.getText(R.string.condition_turn_off)); + } + + @Test + public void onResume_shouldRegisterReceiver() { + mCondition.onResume(); + + verify(mContext).registerReceiver(any(BatterySaverReceiver.class), any(IntentFilter.class)); + } + + @Test + public void onPause_shouldUnregisterReceiver() { + mCondition.onResume(); + mCondition.onPause(); + + verify(mContext).unregisterReceiver(any(BatterySaverReceiver.class)); + } + + @Test + public void refreshState_PowerSaverOn_shouldActivate() { + mPowerManager.setIsPowerSaveMode(true); + + mCondition.refreshState(); + + assertThat(mCondition.isActive()).isTrue(); + } + + @Test + public void refreshState_PowerSaverOff_shouldNotActivate() { + mPowerManager.setIsPowerSaveMode(false); + + mCondition.refreshState(); + + assertThat(mCondition.isActive()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java index 2168a2ad62f..e0877e47217 100644 --- a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java @@ -245,7 +245,7 @@ public class AudioOutputSwitchPreferenceControllerTest { @Override public String getPreferenceKey() { - return null; + return TEST_KEY; } } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java index f3f1c835787..0692c9c6ccf 100644 --- a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java @@ -159,7 +159,7 @@ public class HandsFreeProfileOutputPreferenceControllerTest { /** * One Headset Bluetooth device is available and activated - * Preference should be enabled + * Preference should be visible * Preference summary should be activate device name */ @Test @@ -170,13 +170,13 @@ public class HandsFreeProfileOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isVisible()).isTrue(); assertThat(mPreference.getSummary()).isEqualTo(mBluetoothDevice.getName()); } /** * More than one Headset Bluetooth devices are available, and second device is active. - * Preference should be enabled + * Preference should be visible * Preference summary should be activate device name */ @Test @@ -196,14 +196,14 @@ public class HandsFreeProfileOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isVisible()).isTrue(); assertThat(mPreference.getSummary()).isEqualTo(secondBluetoothDevice.getName()); } /** * Hands Free Profile Bluetooth device(s) are available, but wired headset is plugged in * and activated. - * Preference should be enabled + * Preference should be visible * Preference summary should be "This device" */ @Test @@ -216,14 +216,14 @@ public class HandsFreeProfileOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isVisible()).isTrue(); assertThat(mPreference.getSummary()).isEqualTo( mContext.getText(R.string.media_output_default_summary)); } /** * No available Headset BT devices - * Preference should be disabled + * Preference should be invisible * Preference summary should be "This device" */ @Test @@ -234,7 +234,7 @@ public class HandsFreeProfileOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isFalse(); + assertThat(mPreference.isVisible()).isFalse(); assertThat(mPreference.getSummary()).isEqualTo( mContext.getText(R.string.media_output_default_summary)); } diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java index 1c7c1c4c7b6..b62e6b388d9 100644 --- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java @@ -160,7 +160,7 @@ public class MediaOutputPreferenceControllerTest { /** * On going call state: - * Preference should be disabled + * Preference should be invisible * Default string should be "Unavailable during calls" */ @Test @@ -169,14 +169,14 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isFalse(); + assertThat(mPreference.isVisible()).isFalse(); assertThat(mPreference.getSummary()).isEqualTo( mContext.getText(R.string.media_out_summary_ongoing_call_state)); } /** * No available A2dp BT devices: - * Preference should be disabled + * Preference should be invisible * Preference summary should be "This device" */ @Test @@ -187,14 +187,14 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isFalse(); + assertThat(mPreference.isVisible()).isFalse(); String defaultString = mContext.getString(R.string.media_output_default_summary); assertThat(mPreference.getSummary()).isEqualTo(defaultString); } /** * Media stream is captured by something else (cast device): - * Preference should be disabled + * Preference should be invisible * Preference summary should be "unavailable" */ @Test @@ -203,14 +203,14 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isFalse(); + assertThat(mPreference.isVisible()).isFalse(); String defaultString = mContext.getString(R.string.media_output_summary_unavailable); assertThat(mPreference.getSummary()).isEqualTo(defaultString); } /** * One A2DP Bluetooth device is available and active. - * Preference should be enabled + * Preference should be visible * Preference summary should be activate device name */ @Test @@ -221,13 +221,13 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isVisible()).isTrue(); assertThat(mPreference.getSummary()).isEqualTo(mBluetoothDevice.getName()); } /** * More than one A2DP Bluetooth devices are available, and second device is active. - * Preference should be enabled + * Preference should be visible * Preference summary should be activate device name */ @Test @@ -247,13 +247,13 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isVisible()).isTrue(); assertThat(mPreference.getSummary()).isEqualTo(secondBluetoothDevice.getName()); } /** * A2DP Bluetooth device(s) are available, but wired headset is plugged in and activated - * Preference should be enabled + * Preference should be visible * Preference summary should be "This device" */ @Test @@ -266,7 +266,7 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isVisible()).isTrue(); String defaultString = mContext.getString(R.string.media_output_default_summary); assertThat(mPreference.getSummary()).isEqualTo(defaultString); } @@ -274,7 +274,7 @@ public class MediaOutputPreferenceControllerTest { /** * A2DP Bluetooth device(s) are available, but current device speaker is activated - * Preference should be enabled + * Preference should be visible * Preference summary should be "This device" */ @Test @@ -285,7 +285,7 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isVisible()).isTrue(); String defaultString = mContext.getString(R.string.media_output_default_summary); assertThat(mPreference.getSummary()).isEqualTo(defaultString); } diff --git a/tests/robotests/src/com/android/settings/widget/HotspotApBandSelectionPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/HotspotApBandSelectionPreferenceTest.java index 6bfc968a12a..0ffda3baa96 100644 --- a/tests/robotests/src/com/android/settings/widget/HotspotApBandSelectionPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/widget/HotspotApBandSelectionPreferenceTest.java @@ -115,6 +115,21 @@ public class HotspotApBandSelectionPreferenceTest { assertThat(mPreference.mShouldRestore).isFalse(); } + @Test + public void onSaveInstanceState_doesNotCrashWhenViewGone() { + mPreference.setExistingConfigValue(WifiConfiguration.AP_BAND_2GHZ); + mPreference.onBindDialogView(mLayout); + // When the device dozes the view and dialog can become null + mPreference.mBox5G = null; + mPreference.mBox2G = null; + ReflectionHelpers.setField(mPreference, "mFragment", null); + + // make sure it does not crash and state is not restored + Parcelable parcelable = mPreference.onSaveInstanceState(); + mPreference.onRestoreInstanceState(parcelable); + assertThat(mPreference.mShouldRestore).isFalse(); + } + @Test public void onSaveInstanceState_presentWhenDialogPresent() { mPreference.setExistingConfigValue(WifiConfiguration.AP_BAND_2GHZ);