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