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
This commit is contained in:
Sally
2020-10-21 23:50:12 +00:00
parent fded2b6d13
commit 9ee2301f71
6 changed files with 296 additions and 2 deletions

View File

@@ -114,7 +114,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
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
</string>
<!-- The tiles to display in QuickSettings -->

View File

@@ -1014,6 +1014,11 @@
<string name="quick_settings_dark_mode_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>
<!-- QuickSettings: Secondary text for when the Dark theme or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
<string name="quick_settings_dark_mode_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
<!-- TODO(b/170970602): remove translatable=false when RBC has official name and strings -->
<!-- QuickSettings: Label for the toggle that controls whether Reduce Bright Colors is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_reduce_bright_colors_label" translatable="false">Reduce Bright Colors</string>
<!-- QuickSettings: Secondary text for intensity level of Reduce Bright Colors. [CHAR LIMIT=NONE] -->
<string name="quick_settings_reduce_bright_colors_secondary_label" translatable="false"> <xliff:g id="intensity" example="50">%d</xliff:g>%% reduction</string>
<!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
<string name="quick_settings_nfc_label">NFC</string>

View File

@@ -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<GarbageMonitor.MemoryTile> mMemoryTileProvider;
private final Provider<UiModeNightTile> mUiModeNightTileProvider;
private final Provider<ScreenRecordTile> mScreenRecordTileProvider;
private final Provider<ReduceBrightColorsTile> mReduceBrightColorsTileProvider;
private final Lazy<QSHost> mQsHostLazy;
private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -105,7 +107,8 @@ public class QSFactoryImpl implements QSFactory {
Provider<NfcTile> nfcTileProvider,
Provider<GarbageMonitor.MemoryTile> memoryTileProvider,
Provider<UiModeNightTile> uiModeNightTileProvider,
Provider<ScreenRecordTile> screenRecordTileProvider) {
Provider<ScreenRecordTile> screenRecordTileProvider,
Provider<ReduceBrightColorsTile> 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

View File

@@ -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<QSTile.BooleanState> {
//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;
}
}

View File

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

View File

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