Loading packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java +9 −4 Original line number Diff line number Diff line Loading @@ -54,19 +54,23 @@ public abstract class SecureSetting extends ContentObserver implements Listenabl } public int getValue() { return mSecureSettings.getIntForUser(mSettingName, mDefaultValue, mUserId); return mListening ? mObservedValue : getValueFromProvider(); } public void setValue(int value) { mSecureSettings.putIntForUser(mSettingName, value, mUserId); } private int getValueFromProvider() { return mSecureSettings.getIntForUser(mSettingName, mDefaultValue, mUserId); } @Override public void setListening(boolean listening) { if (listening == mListening) return; mListening = listening; if (listening) { mObservedValue = getValue(); mObservedValue = getValueFromProvider(); mSecureSettings.registerContentObserverForUser( mSecureSettings.getUriFor(mSettingName), false, this, mUserId); } else { Loading @@ -77,9 +81,10 @@ public abstract class SecureSetting extends ContentObserver implements Listenabl @Override public void onChange(boolean selfChange) { final int value = getValue(); handleValueChanged(value, value != mObservedValue); final int value = getValueFromProvider(); final boolean changed = value != mObservedValue; mObservedValue = value; handleValueChanged(value, changed); } public void setUserId(int userId) { Loading packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +31 −5 Original line number Diff line number Diff line Loading @@ -61,10 +61,12 @@ import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.SecureSetting; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.volume.ZenModePanel; import javax.inject.Inject; Loading @@ -81,6 +83,7 @@ public class DndTile extends QSTileImpl<BooleanState> { private final ZenModeController mController; private final DndDetailAdapter mDetailAdapter; private final SharedPreferences mSharedPreferences; private final SecureSetting mSettingZenDuration; private boolean mListening; private boolean mShowingDetail; Loading @@ -96,7 +99,8 @@ public class DndTile extends QSTileImpl<BooleanState> { ActivityStarter activityStarter, QSLogger qsLogger, ZenModeController zenModeController, @Main SharedPreferences sharedPreferences @Main SharedPreferences sharedPreferences, SecureSettings secureSettings ) { super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); Loading @@ -104,8 +108,17 @@ public class DndTile extends QSTileImpl<BooleanState> { mSharedPreferences = sharedPreferences; mDetailAdapter = new DndDetailAdapter(); mController.observe(getLifecycle(), mZenCallback); mSettingZenDuration = new SecureSetting(secureSettings, mUiHandler, Settings.Secure.ZEN_DURATION, getHost().getUserId()) { @Override protected void handleValueChanged(int value, boolean observedChange) { refreshState(); } }; } public static void setVisible(Context context, boolean visible) { Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible); } Loading Loading @@ -144,14 +157,18 @@ public class DndTile extends QSTileImpl<BooleanState> { if (mState.value) { mController.setZen(ZEN_MODE_OFF, null, TAG); } else { showDetail(true); enableZenMode(view); } } @Override public void showDetail(boolean show) { int zenDuration = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ZEN_DURATION, 0); protected void handleUserSwitch(int newUserId) { super.handleUserSwitch(newUserId); mSettingZenDuration.setUserId(newUserId); } private void enableZenMode(@Nullable View view) { int zenDuration = mSettingZenDuration.getValue(); boolean showOnboarding = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0 && Settings.Secure.getInt(mContext.getContentResolver(), Loading Loading @@ -270,6 +287,8 @@ public class DndTile extends QSTileImpl<BooleanState> { state.dualLabelContentDescription = mContext.getResources().getString( R.string.accessibility_quick_settings_open_settings, getTileLabel()); state.expandedAccessibilityClassName = Switch.class.getName(); state.forceExpandIcon = mSettingZenDuration.getValue() == Settings.Secure.ZEN_DURATION_PROMPT; } @Override Loading @@ -296,6 +315,13 @@ public class DndTile extends QSTileImpl<BooleanState> { } else { Prefs.unregisterListener(mContext, mPrefListener); } mSettingZenDuration.setListening(listening); } @Override protected void handleDestroy() { super.handleDestroy(); mSettingZenDuration.setListening(false); } @Override Loading packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt 0 → 100644 +150 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.systemui.qs.tiles import android.content.ContextWrapper import android.content.SharedPreferences import android.os.Handler import android.provider.Settings import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.logging.QSLogger import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.SecureSettings import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations import java.io.File @SmallTest @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) class DndTileTest : SysuiTestCase() { companion object { private const val DEFAULT_USER = 0 private const val KEY = Settings.Secure.ZEN_DURATION } @Mock private lateinit var qsHost: QSHost @Mock private lateinit var metricsLogger: MetricsLogger @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var zenModeController: ZenModeController @Mock private lateinit var sharedPreferences: SharedPreferences private lateinit var secureSettings: SecureSettings private lateinit var testableLooper: TestableLooper private lateinit var tile: DndTile @Before fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) secureSettings = FakeSettings() Mockito.`when`(qsHost.userId).thenReturn(DEFAULT_USER) Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) val wrappedContext = object : ContextWrapper(context) { override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { return sharedPreferences } } Mockito.`when`(qsHost.context).thenReturn(wrappedContext) tile = DndTile( qsHost, testableLooper.looper, Handler(testableLooper.looper), FalsingManagerFake(), metricsLogger, statusBarStateController, activityStarter, qsLogger, zenModeController, sharedPreferences, secureSettings ) } @After fun tearDown() { tile.handleSetListening(false) } @Test fun testForceExpandIcon_durationAskAlways_true() { secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) tile.refreshState() testableLooper.processAllMessages() assertThat(tile.state.forceExpandIcon).isTrue() } @Test fun testForceExpandIcon_durationNotAskAlways_false() { secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) tile.refreshState() testableLooper.processAllMessages() assertThat(tile.state.forceExpandIcon).isFalse() } @Test fun testForceExpandIcon_changeWhileListening() { secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) tile.refreshState() testableLooper.processAllMessages() assertThat(tile.state.forceExpandIcon).isFalse() tile.handleSetListening(true) secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) testableLooper.processAllMessages() assertThat(tile.state.forceExpandIcon).isTrue() } } No newline at end of file Loading
packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java +9 −4 Original line number Diff line number Diff line Loading @@ -54,19 +54,23 @@ public abstract class SecureSetting extends ContentObserver implements Listenabl } public int getValue() { return mSecureSettings.getIntForUser(mSettingName, mDefaultValue, mUserId); return mListening ? mObservedValue : getValueFromProvider(); } public void setValue(int value) { mSecureSettings.putIntForUser(mSettingName, value, mUserId); } private int getValueFromProvider() { return mSecureSettings.getIntForUser(mSettingName, mDefaultValue, mUserId); } @Override public void setListening(boolean listening) { if (listening == mListening) return; mListening = listening; if (listening) { mObservedValue = getValue(); mObservedValue = getValueFromProvider(); mSecureSettings.registerContentObserverForUser( mSecureSettings.getUriFor(mSettingName), false, this, mUserId); } else { Loading @@ -77,9 +81,10 @@ public abstract class SecureSetting extends ContentObserver implements Listenabl @Override public void onChange(boolean selfChange) { final int value = getValue(); handleValueChanged(value, value != mObservedValue); final int value = getValueFromProvider(); final boolean changed = value != mObservedValue; mObservedValue = value; handleValueChanged(value, changed); } public void setUserId(int userId) { Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +31 −5 Original line number Diff line number Diff line Loading @@ -61,10 +61,12 @@ import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.SecureSetting; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.volume.ZenModePanel; import javax.inject.Inject; Loading @@ -81,6 +83,7 @@ public class DndTile extends QSTileImpl<BooleanState> { private final ZenModeController mController; private final DndDetailAdapter mDetailAdapter; private final SharedPreferences mSharedPreferences; private final SecureSetting mSettingZenDuration; private boolean mListening; private boolean mShowingDetail; Loading @@ -96,7 +99,8 @@ public class DndTile extends QSTileImpl<BooleanState> { ActivityStarter activityStarter, QSLogger qsLogger, ZenModeController zenModeController, @Main SharedPreferences sharedPreferences @Main SharedPreferences sharedPreferences, SecureSettings secureSettings ) { super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); Loading @@ -104,8 +108,17 @@ public class DndTile extends QSTileImpl<BooleanState> { mSharedPreferences = sharedPreferences; mDetailAdapter = new DndDetailAdapter(); mController.observe(getLifecycle(), mZenCallback); mSettingZenDuration = new SecureSetting(secureSettings, mUiHandler, Settings.Secure.ZEN_DURATION, getHost().getUserId()) { @Override protected void handleValueChanged(int value, boolean observedChange) { refreshState(); } }; } public static void setVisible(Context context, boolean visible) { Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible); } Loading Loading @@ -144,14 +157,18 @@ public class DndTile extends QSTileImpl<BooleanState> { if (mState.value) { mController.setZen(ZEN_MODE_OFF, null, TAG); } else { showDetail(true); enableZenMode(view); } } @Override public void showDetail(boolean show) { int zenDuration = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ZEN_DURATION, 0); protected void handleUserSwitch(int newUserId) { super.handleUserSwitch(newUserId); mSettingZenDuration.setUserId(newUserId); } private void enableZenMode(@Nullable View view) { int zenDuration = mSettingZenDuration.getValue(); boolean showOnboarding = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0 && Settings.Secure.getInt(mContext.getContentResolver(), Loading Loading @@ -270,6 +287,8 @@ public class DndTile extends QSTileImpl<BooleanState> { state.dualLabelContentDescription = mContext.getResources().getString( R.string.accessibility_quick_settings_open_settings, getTileLabel()); state.expandedAccessibilityClassName = Switch.class.getName(); state.forceExpandIcon = mSettingZenDuration.getValue() == Settings.Secure.ZEN_DURATION_PROMPT; } @Override Loading @@ -296,6 +315,13 @@ public class DndTile extends QSTileImpl<BooleanState> { } else { Prefs.unregisterListener(mContext, mPrefListener); } mSettingZenDuration.setListening(listening); } @Override protected void handleDestroy() { super.handleDestroy(); mSettingZenDuration.setListening(false); } @Override Loading
packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt 0 → 100644 +150 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.systemui.qs.tiles import android.content.ContextWrapper import android.content.SharedPreferences import android.os.Handler import android.provider.Settings import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.logging.QSLogger import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.SecureSettings import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations import java.io.File @SmallTest @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) class DndTileTest : SysuiTestCase() { companion object { private const val DEFAULT_USER = 0 private const val KEY = Settings.Secure.ZEN_DURATION } @Mock private lateinit var qsHost: QSHost @Mock private lateinit var metricsLogger: MetricsLogger @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var zenModeController: ZenModeController @Mock private lateinit var sharedPreferences: SharedPreferences private lateinit var secureSettings: SecureSettings private lateinit var testableLooper: TestableLooper private lateinit var tile: DndTile @Before fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) secureSettings = FakeSettings() Mockito.`when`(qsHost.userId).thenReturn(DEFAULT_USER) Mockito.`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger) val wrappedContext = object : ContextWrapper(context) { override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { return sharedPreferences } } Mockito.`when`(qsHost.context).thenReturn(wrappedContext) tile = DndTile( qsHost, testableLooper.looper, Handler(testableLooper.looper), FalsingManagerFake(), metricsLogger, statusBarStateController, activityStarter, qsLogger, zenModeController, sharedPreferences, secureSettings ) } @After fun tearDown() { tile.handleSetListening(false) } @Test fun testForceExpandIcon_durationAskAlways_true() { secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) tile.refreshState() testableLooper.processAllMessages() assertThat(tile.state.forceExpandIcon).isTrue() } @Test fun testForceExpandIcon_durationNotAskAlways_false() { secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) tile.refreshState() testableLooper.processAllMessages() assertThat(tile.state.forceExpandIcon).isFalse() } @Test fun testForceExpandIcon_changeWhileListening() { secureSettings.putIntForUser(KEY, 60, DEFAULT_USER) tile.refreshState() testableLooper.processAllMessages() assertThat(tile.state.forceExpandIcon).isFalse() tile.handleSetListening(true) secureSettings.putIntForUser(KEY, Settings.Secure.ZEN_DURATION_PROMPT, DEFAULT_USER) testableLooper.processAllMessages() assertThat(tile.state.forceExpandIcon).isTrue() } } No newline at end of file