From 9ee2301f7115987f2e4309e53a95cb1d413029df Mon Sep 17 00:00:00 2001 From: Sally Date: Wed, 21 Oct 2020 23:50:12 +0000 Subject: [PATCH] Add a QS tile for Reduce Bright Colors The flow will be the same as that of our other accessibility feature, Color Inversion. 1) RBC is in the stock list of tiles users can move to the panel 2) (TODO) The first time the feature is turned on, it gets moved to the panel Long-pressing the tile navigates to the RBC subpage, where users can adjust the intensity slider. TODOs: call into CDS for config availability, get a tile icon, update strings, set a callback for adding tile, so the first time the feature is turned on, it gets moved to the panel Test: long-pressing opens the RBC settings page, atest ReduceBrightColorsTileTest Bug: b/128465252 Change-Id: I26959fedf71298830fa5325307f555c8e2bc3901 --- packages/SystemUI/res/values/config.xml | 2 +- packages/SystemUI/res/values/strings.xml | 5 + .../systemui/qs/tileimpl/QSFactoryImpl.java | 8 +- .../qs/tiles/ReduceBrightColorsTile.java | 139 +++++++++++++++++ .../statusbar/phone/AutoTileManager.java | 4 + .../qs/tiles/ReduceBrightColorsTileTest.java | 140 ++++++++++++++++++ 6 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 1a72fc2318156..4707537056ba5 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -114,7 +114,7 @@ - wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse + wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 773ef7dcf59fa..b92f444be5fb6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1014,6 +1014,11 @@ On at %s Until %s + + + Reduce Bright Colors + + %d%% reduction NFC diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 8e33496e73af3..24c0fd76d8276 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -40,6 +40,7 @@ import com.android.systemui.qs.tiles.HotspotTile; import com.android.systemui.qs.tiles.LocationTile; import com.android.systemui.qs.tiles.NfcTile; import com.android.systemui.qs.tiles.NightDisplayTile; +import com.android.systemui.qs.tiles.ReduceBrightColorsTile; import com.android.systemui.qs.tiles.RotationLockTile; import com.android.systemui.qs.tiles.ScreenRecordTile; import com.android.systemui.qs.tiles.UiModeNightTile; @@ -78,6 +79,7 @@ public class QSFactoryImpl implements QSFactory { private final Provider mMemoryTileProvider; private final Provider mUiModeNightTileProvider; private final Provider mScreenRecordTileProvider; + private final Provider mReduceBrightColorsTileProvider; private final Lazy mQsHostLazy; private final Provider mCustomTileBuilderProvider; @@ -105,7 +107,8 @@ public class QSFactoryImpl implements QSFactory { Provider nfcTileProvider, Provider memoryTileProvider, Provider uiModeNightTileProvider, - Provider screenRecordTileProvider) { + Provider screenRecordTileProvider, + Provider reduceBrightColorsTileProvider) { mQsHostLazy = qsHostLazy; mCustomTileBuilderProvider = customTileBuilderProvider; @@ -129,6 +132,7 @@ public class QSFactoryImpl implements QSFactory { mMemoryTileProvider = memoryTileProvider; mUiModeNightTileProvider = uiModeNightTileProvider; mScreenRecordTileProvider = screenRecordTileProvider; + mReduceBrightColorsTileProvider = reduceBrightColorsTileProvider; } public QSTile createTile(String tileSpec) { @@ -180,6 +184,8 @@ public class QSFactoryImpl implements QSFactory { return mUiModeNightTileProvider.get(); case "screenrecord": return mScreenRecordTileProvider.get(); + case "reduce_brightness": + return mReduceBrightColorsTileProvider.get(); } // Custom tiles diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java new file mode 100644 index 0000000000000..84c7611478cd7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2020 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.Intent; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.service.quicksettings.Tile; +import android.text.TextUtils; +import android.widget.Switch; + +import com.android.internal.logging.MetricsLogger; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.qs.QSTile; +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.settings.UserTracker; +import com.android.systemui.util.settings.SecureSettings; + +import javax.inject.Inject; + +/** Quick settings tile: Reduce Bright Colors **/ +public class ReduceBrightColorsTile extends QSTileImpl { + + //TODO(b/170973645): get icon drawable + private final Icon mIcon = null; + private final SecureSetting mActivatedSetting; + + @Inject + public ReduceBrightColorsTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger, + UserTracker userTracker, + SecureSettings secureSettings + ) { + super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, + activityStarter, qsLogger); + + mActivatedSetting = new SecureSetting(secureSettings, mainHandler, + Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, userTracker.getUserId()) { + @Override + protected void handleValueChanged(int value, boolean observedChange) { + refreshState(); + } + }; + } + @Override + public boolean isAvailable() { + // TODO(b/170970675): Call into ColorDisplayService to get availability/config status + return true; + } + + @Override + protected void handleDestroy() { + super.handleDestroy(); + mActivatedSetting.setListening(false); + } + + @Override + public BooleanState newTileState() { + return new BooleanState(); + } + + @Override + public void handleSetListening(boolean listening) { + super.handleSetListening(listening); + mActivatedSetting.setListening(listening); + } + + @Override + protected void handleUserSwitch(int newUserId) { + mActivatedSetting.setUserId(newUserId); + refreshState(); + } + + @Override + public Intent getLongClickIntent() { + return new Intent(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS); + } + + @Override + protected void handleClick() { + mActivatedSetting.setValue(mState.value ? 0 : 1); + } + + @Override + public CharSequence getTileLabel() { + return mContext.getString(R.string.quick_settings_reduce_bright_colors_label); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + state.value = mActivatedSetting.getValue() == 1; + state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; + state.label = mContext.getString(R.string.quick_settings_reduce_bright_colors_label); + state.expandedAccessibilityClassName = Switch.class.getName(); + state.contentDescription = state.label; + + final int intensity = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mActivatedSetting.getCurrentUser()); + state.secondaryLabel = state.value ? mContext.getString( + R.string.quick_settings_reduce_bright_colors_secondary_label, intensity) : ""; + + state.contentDescription = TextUtils.isEmpty(state.secondaryLabel) + ? state.label + : TextUtils.concat(state.label, ", ", state.secondaryLabel); + } + + @Override + public int getMetricsCategory() { + return 0; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java index 3622f1cd3952d..e40c262765ea2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java @@ -53,6 +53,7 @@ public class AutoTileManager implements UserAwareController { public static final String WORK = "work"; public static final String NIGHT = "night"; public static final String CAST = "cast"; + public static final String BRIGHTNESS = "reduce_brightness"; static final String SETTING_SEPARATOR = ":"; private UserHandle mCurrentUser; @@ -124,6 +125,9 @@ public class AutoTileManager implements UserAwareController { mCastController.addCallback(mCastCallback); } + // TODO(b/170970675): Set a listener/controller and callback for Reduce Bright Colors + // state changes. Call into ColorDisplayService to get availability/config status + int settingsN = mAutoAddSettingList.size(); for (int i = 0; i < settingsN; i++) { if (!mAutoTracker.isAdded(mAutoAddSettingList.get(i).mSpec)) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java new file mode 100644 index 0000000000000..78af20f9db31a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 static junit.framework.Assert.assertEquals; + +import static org.mockito.Mockito.when; + +import android.os.Handler; +import android.provider.Settings; +import android.service.quicksettings.Tile; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.MetricsLogger; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.settings.UserTracker; +import com.android.systemui.util.settings.FakeSettings; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +@SmallTest +public class ReduceBrightColorsTileTest extends SysuiTestCase { + @Mock + private QSTileHost mHost; + @Mock + private MetricsLogger mMetricsLogger; + @Mock + private StatusBarStateController mStatusBarStateController; + @Mock + private ActivityStarter mActivityStarter; + @Mock + private QSLogger mQSLogger; + @Mock + private UserTracker mUserTracker; + + private FakeSettings mFakeSettings; + private TestableLooper mTestableLooper; + private ReduceBrightColorsTile mTile; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mTestableLooper = TestableLooper.get(this); + + when(mHost.getContext()).thenReturn(mContext); + mFakeSettings = new FakeSettings(); + + mTile = new ReduceBrightColorsTile( + mHost, + mTestableLooper.getLooper(), + new Handler(mTestableLooper.getLooper()), + mMetricsLogger, + mStatusBarStateController, + mActivityStarter, + mQSLogger, + mUserTracker, + mFakeSettings + ); + } + + @Test + public void testNotActive() { + mTile.refreshState(); + mTestableLooper.processAllMessages(); + + assertEquals(Tile.STATE_INACTIVE, mTile.getState().state); + assertEquals(mTile.getState().label.toString(), + mContext.getString(R.string.quick_settings_reduce_bright_colors_label)); + assertEquals(mTile.getState().secondaryLabel.toString(), ""); + } + + @Test + public void testActive() { + mFakeSettings.putIntForUser( + Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, + 1, + mUserTracker.getUserId()); + mTile.refreshState(); + mTestableLooper.processAllMessages(); + + assertActiveState(); + } + + @Test + public void testActive_clicked_isActive() { + mTile.refreshState(); + mTestableLooper.processAllMessages(); + // Validity check + assertEquals(Tile.STATE_INACTIVE, mTile.getState().state); + + mTile.handleClick(); + mTile.refreshState(); + mTestableLooper.processAllMessages(); + + assertActiveState(); + } + + private void assertActiveState() { + assertEquals(Tile.STATE_ACTIVE, mTile.getState().state); + assertEquals(mTile.getState().label.toString(), + mContext.getString(R.string.quick_settings_reduce_bright_colors_label)); + + final int intensity = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mUserTracker.getUserId()); + + assertEquals( + mContext.getString( + R.string.quick_settings_reduce_bright_colors_secondary_label, intensity), + mTile.getState().secondaryLabel.toString()); + } +}