Merge "Add auto tiles by config" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
01702af7a3
@@ -3603,12 +3603,6 @@
|
||||
<!-- Whether the device supports quick settings and its associated APIs -->
|
||||
<bool name="config_quickSettingsSupported">true</bool>
|
||||
|
||||
<!-- Comma separated list of extra quick settings tiles to be added to the default set as
|
||||
defined in SystemUi (com.android.systemui.R.string.quick_settings_tiles_default).
|
||||
Custom tiles (TileService) must be specified as "custom(pkg_name/class_in_package)"
|
||||
(without the quotes, both absolute and relative class works). -->
|
||||
<string name="config_defaultExtraQuickSettingsTiles" translatable="false"></string>
|
||||
|
||||
<!-- The component name, flattened to a string, for the default autofill service
|
||||
to enabled for an user. This service must be trusted, as it can be activated
|
||||
without explicit consent of the user. If no autofill service with the
|
||||
|
||||
@@ -3447,7 +3447,6 @@
|
||||
<java-symbol type="string" name="etws_primary_default_message_others" />
|
||||
|
||||
<java-symbol type="bool" name="config_quickSettingsSupported" />
|
||||
<java-symbol type="string" name="config_defaultExtraQuickSettingsTiles" />
|
||||
|
||||
<java-symbol type="style" name="Theme.DeviceDefault.QuickSettings" />
|
||||
|
||||
|
||||
@@ -128,6 +128,13 @@
|
||||
night,dark,dnd,flashlight,rotation,location
|
||||
</string>
|
||||
|
||||
<!-- Tiles to auto add to Quick Settings upon first change of a given secure setting.
|
||||
The syntax is setting-name:spec. If the tile is a TileService, the spec should be specified
|
||||
as custom(package/class). Relative class name is supported. -->
|
||||
<string-array name="config_quickSettingsAutoAdd" translatable="false">
|
||||
<item>accessibility_display_inversion_enabled:inversion</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Whether or not the RSSI tile is capitalized or not. -->
|
||||
<bool name="quick_settings_rssi_tile_capitalization">true</bool>
|
||||
|
||||
|
||||
@@ -454,11 +454,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
|
||||
|
||||
final Resources res = context.getResources();
|
||||
final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
|
||||
final String extraTileList = res.getString(
|
||||
com.android.internal.R.string.config_defaultExtraQuickSettingsTiles);
|
||||
|
||||
tiles.addAll(Arrays.asList(defaultTileList.split(",")));
|
||||
tiles.addAll(Arrays.asList(extraTileList.split(",")));
|
||||
if (Build.IS_DEBUGGABLE
|
||||
&& GarbageMonitor.MemoryTile.ADD_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) {
|
||||
tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
|
||||
|
||||
@@ -88,4 +88,12 @@ public abstract class SecureSetting extends ContentObserver implements Listenabl
|
||||
public int getCurrentUser() {
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return mSettingName;
|
||||
}
|
||||
|
||||
public boolean isListening() {
|
||||
return mListening;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,19 @@
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.display.ColorDisplayManager;
|
||||
import android.hardware.display.NightDisplayListener;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
import com.android.systemui.qs.AutoAddTracker;
|
||||
import com.android.systemui.qs.QSTileHost;
|
||||
import com.android.systemui.qs.SecureSetting;
|
||||
import com.android.systemui.qs.external.CustomTile;
|
||||
import com.android.systemui.statusbar.policy.CastController;
|
||||
import com.android.systemui.statusbar.policy.CastController.CastDevice;
|
||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||
@@ -32,18 +35,24 @@ import com.android.systemui.statusbar.policy.DataSaverController.Listener;
|
||||
import com.android.systemui.statusbar.policy.HotspotController;
|
||||
import com.android.systemui.statusbar.policy.HotspotController.Callback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Manages which tiles should be automatically added to QS.
|
||||
*/
|
||||
public class AutoTileManager {
|
||||
private static final String TAG = "AutoTileManager";
|
||||
|
||||
public static final String HOTSPOT = "hotspot";
|
||||
public static final String SAVER = "saver";
|
||||
public static final String INVERSION = "inversion";
|
||||
public static final String WORK = "work";
|
||||
public static final String NIGHT = "night";
|
||||
public static final String CAST = "cast";
|
||||
public static final String SETTING_SEPARATOR = ":";
|
||||
|
||||
private final Context mContext;
|
||||
private final QSTileHost mHost;
|
||||
@@ -54,6 +63,7 @@ public class AutoTileManager {
|
||||
private final ManagedProfileController mManagedProfileController;
|
||||
private final NightDisplayListener mNightDisplayListener;
|
||||
private final CastController mCastController;
|
||||
private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
|
||||
@@ -78,21 +88,6 @@ public class AutoTileManager {
|
||||
if (!mAutoTracker.isAdded(SAVER)) {
|
||||
dataSaverController.addCallback(mDataSaverListener);
|
||||
}
|
||||
if (!mAutoTracker.isAdded(INVERSION)) {
|
||||
mColorsSetting = new SecureSetting(mContext, mHandler,
|
||||
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
|
||||
@Override
|
||||
protected void handleValueChanged(int value, boolean observedChange) {
|
||||
if (mAutoTracker.isAdded(INVERSION)) return;
|
||||
if (value != 0) {
|
||||
mHost.addTile(INVERSION);
|
||||
mAutoTracker.setTileAdded(INVERSION);
|
||||
mHandler.post(() -> mColorsSetting.setListening(false));
|
||||
}
|
||||
}
|
||||
};
|
||||
mColorsSetting.setListening(true);
|
||||
}
|
||||
if (!mAutoTracker.isAdded(WORK)) {
|
||||
managedProfileController.addCallback(mProfileCallback);
|
||||
}
|
||||
@@ -103,12 +98,10 @@ public class AutoTileManager {
|
||||
if (!mAutoTracker.isAdded(CAST)) {
|
||||
castController.addCallback(mCastCallback);
|
||||
}
|
||||
populateSettingsList();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (mColorsSetting != null) {
|
||||
mColorsSetting.setListening(false);
|
||||
}
|
||||
mAutoTracker.destroy();
|
||||
mHotspotController.removeCallback(mHotspotCallback);
|
||||
mDataSaverController.removeCallback(mDataSaverListener);
|
||||
@@ -117,6 +110,42 @@ public class AutoTileManager {
|
||||
mNightDisplayListener.setCallback(null);
|
||||
}
|
||||
mCastController.removeCallback(mCastCallback);
|
||||
int settingsN = mAutoAddSettingList.size();
|
||||
for (int i = 0; i < settingsN; i++) {
|
||||
mAutoAddSettingList.get(i).setListening(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a list with the pairs setting:spec in the config resource.
|
||||
* <p>
|
||||
* This will only create {@link AutoAddSetting} objects for those tiles that have not been
|
||||
* auto-added before, and set the corresponding {@link ContentObserver} to listening.
|
||||
*/
|
||||
private void populateSettingsList() {
|
||||
String [] autoAddList;
|
||||
try {
|
||||
autoAddList = mContext.getResources().getStringArray(
|
||||
R.array.config_quickSettingsAutoAdd);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
Log.w(TAG, "Missing config resource");
|
||||
return;
|
||||
}
|
||||
// getStringArray returns @NotNull, so if we got here, autoAddList is not null
|
||||
for (String tile : autoAddList) {
|
||||
String[] split = tile.split(SETTING_SEPARATOR);
|
||||
if (split.length == 2) {
|
||||
String setting = split[0];
|
||||
String spec = split[1];
|
||||
if (!mAutoTracker.isAdded(spec)) {
|
||||
AutoAddSetting s = new AutoAddSetting(mContext, mHandler, setting, spec);
|
||||
mAutoAddSettingList.add(s);
|
||||
s.setListening(true);
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Malformed item in array: " + tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unmarkTileAsAutoAdded(String tabSpec) {
|
||||
@@ -139,8 +168,6 @@ public class AutoTileManager {
|
||||
}
|
||||
};
|
||||
|
||||
private SecureSetting mColorsSetting;
|
||||
|
||||
private final DataSaverController.Listener mDataSaverListener = new Listener() {
|
||||
@Override
|
||||
public void onDataSaverChanged(boolean isDataSaving) {
|
||||
@@ -213,4 +240,47 @@ public class AutoTileManager {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@VisibleForTesting
|
||||
protected SecureSetting getSecureSettingForKey(String key) {
|
||||
for (SecureSetting s : mAutoAddSettingList) {
|
||||
if (Objects.equals(key, s.getKey())) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks tiles that should be auto added when a setting changes.
|
||||
* <p>
|
||||
* When the setting changes to a value different from 0, if the tile has not been auto added
|
||||
* before, it will be added and the listener will be stopped.
|
||||
*/
|
||||
private class AutoAddSetting extends SecureSetting {
|
||||
private final String mSpec;
|
||||
|
||||
AutoAddSetting(Context context, Handler handler, String setting, String tileSpec) {
|
||||
super(context, handler, setting);
|
||||
mSpec = tileSpec;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleValueChanged(int value, boolean observedChange) {
|
||||
if (mAutoTracker.isAdded(mSpec)) {
|
||||
// This should not be listening anymore
|
||||
mHandler.post(() -> setListening(false));
|
||||
return;
|
||||
}
|
||||
if (value != 0) {
|
||||
if (mSpec.startsWith(CustomTile.PREFIX)) {
|
||||
mHost.addTile(CustomTile.getComponentFromSpec(mSpec));
|
||||
} else {
|
||||
mHost.addTile(mSpec);
|
||||
}
|
||||
mAutoTracker.setTileAdded(mSpec);
|
||||
mHandler.post(() -> setListening(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,11 +122,6 @@ public class QSTileHostTest extends SysuiTestCase {
|
||||
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger);
|
||||
setUpTileFactory();
|
||||
|
||||
// Override this config so there are no unexpected tiles
|
||||
mContext.getOrCreateTestableResources().addOverride(
|
||||
com.android.internal.R.string.config_defaultExtraQuickSettingsTiles,
|
||||
"");
|
||||
|
||||
Settings.Secure.putStringForUser(mContext.getContentResolver(), QSTileHost.TILES_SETTING,
|
||||
"", ActivityManager.getCurrentUser());
|
||||
}
|
||||
@@ -209,34 +204,6 @@ public class QSTileHostTest extends SysuiTestCase {
|
||||
verify(mQSLogger).logTileAdded("spec1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultAndExtra() {
|
||||
mContext.getOrCreateTestableResources()
|
||||
.addOverride(R.string.quick_settings_tiles_default, "spec1");
|
||||
mContext.getOrCreateTestableResources().addOverride(
|
||||
com.android.internal.R.string.config_defaultExtraQuickSettingsTiles, "spec2");
|
||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "default");
|
||||
assertEquals(2, mQSTileHost.getTiles().size());
|
||||
QSTile[] elements = mQSTileHost.getTiles().toArray(new QSTile[0]);
|
||||
assertTrue(elements[0] instanceof TestTile1);
|
||||
assertTrue(elements[1] instanceof TestTile2);
|
||||
|
||||
verify(mQSLogger).logTileAdded("spec1");
|
||||
verify(mQSLogger).logTileAdded("spec2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtraCustom() {
|
||||
mContext.getOrCreateTestableResources().addOverride(
|
||||
com.android.internal.R.string.config_defaultExtraQuickSettingsTiles,
|
||||
CUSTOM_TILE_SPEC);
|
||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "default");
|
||||
assertEquals(1, mQSTileHost.getTiles().size());
|
||||
assertEquals(mCustomTile, CollectionUtils.firstOrNull(mQSTileHost.getTiles()));
|
||||
|
||||
verify(mQSLogger).logTileAdded(CUSTOM_TILE_SPEC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoRepeatedSpecs_addTile() {
|
||||
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
|
||||
|
||||
@@ -20,19 +20,24 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.hardware.display.ColorDisplayManager;
|
||||
import android.hardware.display.NightDisplayListener;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.qs.AutoAddTracker;
|
||||
import com.android.systemui.qs.QSTileHost;
|
||||
import com.android.systemui.qs.SecureSetting;
|
||||
import com.android.systemui.statusbar.policy.CastController;
|
||||
import com.android.systemui.statusbar.policy.CastController.CastDevice;
|
||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||
@@ -52,6 +57,13 @@ import java.util.List;
|
||||
@SmallTest
|
||||
public class AutoTileManagerTest extends SysuiTestCase {
|
||||
|
||||
private static final String TEST_SETTING = "setting";
|
||||
private static final String TEST_SPEC = "spec";
|
||||
private static final String TEST_SETTING_COMPONENT = "setting_component";
|
||||
private static final String TEST_COMPONENT = "test_pkg/test_cls";
|
||||
private static final String TEST_CUSTOM_SPEC = "custom(" + TEST_COMPONENT + ")";
|
||||
private static final String SEPARATOR = AutoTileManager.SETTING_SEPARATOR;
|
||||
|
||||
@Mock private QSTileHost mQsTileHost;
|
||||
@Mock private AutoAddTracker mAutoAddTracker;
|
||||
@Mock private CastController mCastController;
|
||||
@@ -61,7 +73,20 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
|
||||
|
||||
mContext.getOrCreateTestableResources().addOverride(
|
||||
R.array.config_quickSettingsAutoAdd,
|
||||
new String[] {
|
||||
TEST_SETTING + SEPARATOR + TEST_SPEC,
|
||||
TEST_SETTING_COMPONENT + SEPARATOR + TEST_CUSTOM_SPEC
|
||||
}
|
||||
);
|
||||
|
||||
mAutoTileManager = createAutoTileManager();
|
||||
}
|
||||
|
||||
private AutoTileManager createAutoTileManager() {
|
||||
return new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
|
||||
Handler.createAsync(TestableLooper.get(this).getLooper()),
|
||||
mock(HotspotController.class),
|
||||
mock(DataSaverController.class),
|
||||
@@ -137,4 +162,72 @@ public class AutoTileManagerTest extends SysuiTestCase {
|
||||
mAutoTileManager.mCastCallback.onCastDevicesChanged();
|
||||
verify(mQsTileHost, never()).addTile("cast");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingTileAdded_onChanged() {
|
||||
changeValue(TEST_SETTING, 1);
|
||||
waitForIdleSync();
|
||||
verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
|
||||
verify(mQsTileHost).addTile(TEST_SPEC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingTileAddedComponent_onChanged() {
|
||||
changeValue(TEST_SETTING_COMPONENT, 1);
|
||||
waitForIdleSync();
|
||||
verify(mAutoAddTracker).setTileAdded(TEST_CUSTOM_SPEC);
|
||||
verify(mQsTileHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingTileAdded_onlyOnce() {
|
||||
changeValue(TEST_SETTING, 1);
|
||||
waitForIdleSync();
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
changeValue(TEST_SETTING, 2);
|
||||
waitForIdleSync();
|
||||
verify(mAutoAddTracker).setTileAdded(TEST_SPEC);
|
||||
verify(mQsTileHost).addTile(TEST_SPEC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingTileNotAdded_onChangedTo0() {
|
||||
changeValue(TEST_SETTING, 0);
|
||||
waitForIdleSync();
|
||||
verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
|
||||
verify(mQsTileHost, never()).addTile(TEST_SPEC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingTileNotAdded_ifPreviouslyAdded() {
|
||||
when(mAutoAddTracker.isAdded(TEST_SPEC)).thenReturn(true);
|
||||
|
||||
changeValue(TEST_SETTING, 1);
|
||||
waitForIdleSync();
|
||||
verify(mAutoAddTracker, never()).setTileAdded(TEST_SPEC);
|
||||
verify(mQsTileHost, never()).addTile(TEST_SPEC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyArray_doesNotCrash() {
|
||||
mContext.getOrCreateTestableResources().addOverride(
|
||||
R.array.config_quickSettingsAutoAdd, new String[0]);
|
||||
createAutoTileManager();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingConfig_doesNotCrash() {
|
||||
mContext.getOrCreateTestableResources().addOverride(
|
||||
R.array.config_quickSettingsAutoAdd, null);
|
||||
createAutoTileManager();
|
||||
}
|
||||
|
||||
// Will only notify if it's listening
|
||||
private void changeValue(String key, int value) {
|
||||
SecureSetting s = mAutoTileManager.getSecureSettingForKey(key);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), key, value);
|
||||
if (s != null && s.isListening()) {
|
||||
s.onChange(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user