Update icon tint color when the user toggles Dark theme
- Reload theme in slice provider when Dark theme mode changes for slices - Reload theme in onCreate of Panel activity for its non-slice header - Remove applyTheme from individual slices Test: robotest Fixes: 153700819 Change-Id: I40a7d2817c4b9100d7b2f2962a69c8a9ce6f7906
This commit is contained in:
@@ -42,6 +42,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@@ -1101,4 +1102,13 @@ public final class Utils extends com.android.settingslib.Utils {
|
|||||||
context.getString(R.string.config_settingsintelligence_package_name));
|
context.getString(R.string.config_settingsintelligence_package_name));
|
||||||
return isSettingsIntelligence;
|
return isSettingsIntelligence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the night mode is enabled.
|
||||||
|
*/
|
||||||
|
public static boolean isNightMode(Context context) {
|
||||||
|
final int currentNightMode =
|
||||||
|
context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||||
|
return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -105,9 +105,6 @@ public class BluetoothDevicesSlice implements CustomSliceable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload theme for switching dark mode on/off
|
|
||||||
mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
|
|
||||||
|
|
||||||
final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
|
final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
|
||||||
.setAccentColor(COLOR_NOT_TINTED);
|
.setAccentColor(COLOR_NOT_TINTED);
|
||||||
|
|
||||||
|
@@ -24,7 +24,6 @@ import android.app.PendingIntent;
|
|||||||
import android.app.UiModeManager;
|
import android.app.UiModeManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
@@ -107,7 +106,7 @@ public class DarkThemeSlice implements CustomSliceable {
|
|||||||
final IconCompat icon =
|
final IconCompat icon =
|
||||||
IconCompat.createWithResource(mContext, R.drawable.dark_theme);
|
IconCompat.createWithResource(mContext, R.drawable.dark_theme);
|
||||||
|
|
||||||
final boolean isChecked = isDarkThemeMode(mContext);
|
final boolean isChecked = Utils.isNightMode(mContext);
|
||||||
if (sPreChecked != isChecked) {
|
if (sPreChecked != isChecked) {
|
||||||
// Dark(Night) mode changed and reset the sSliceClicked.
|
// Dark(Night) mode changed and reset the sSliceClicked.
|
||||||
resetValue(isChecked, false);
|
resetValue(isChecked, false);
|
||||||
@@ -157,7 +156,7 @@ public class DarkThemeSlice implements CustomSliceable {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean isAvailable(Context context) {
|
boolean isAvailable(Context context) {
|
||||||
// check if dark theme mode is enabled or if dark theme scheduling is on.
|
// check if dark theme mode is enabled or if dark theme scheduling is on.
|
||||||
if (isDarkThemeMode(context) || isNightModeScheduled()) {
|
if (Utils.isNightMode(context) || isNightModeScheduled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// checking the current battery level
|
// checking the current battery level
|
||||||
@@ -167,13 +166,6 @@ public class DarkThemeSlice implements CustomSliceable {
|
|||||||
return level <= BATTERY_LEVEL_THRESHOLD;
|
return level <= BATTERY_LEVEL_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static boolean isDarkThemeMode(Context context) {
|
|
||||||
final int currentNightMode =
|
|
||||||
context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
|
||||||
return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetValue(boolean preChecked, boolean clicked) {
|
private void resetValue(boolean preChecked, boolean clicked) {
|
||||||
sPreChecked = preChecked;
|
sPreChecked = preChecked;
|
||||||
sSliceClicked = clicked;
|
sSliceClicked = clicked;
|
||||||
|
@@ -75,8 +75,6 @@ public class MediaOutputGroupSlice implements CustomSliceable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Slice getSlice() {
|
public Slice getSlice() {
|
||||||
// Reload theme for switching dark mode on/off
|
|
||||||
mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
|
|
||||||
final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
|
final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
|
||||||
.setAccentColor(COLOR_NOT_TINTED);
|
.setAccentColor(COLOR_NOT_TINTED);
|
||||||
// Add "Group" row
|
// Add "Group" row
|
||||||
|
@@ -81,9 +81,6 @@ public class MediaOutputSlice implements CustomSliceable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Slice getSlice() {
|
public Slice getSlice() {
|
||||||
// Reload theme for switching dark mode on/off
|
|
||||||
mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
|
|
||||||
|
|
||||||
final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
|
final ListBuilder listBuilder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
|
||||||
.setAccentColor(COLOR_NOT_TINTED);
|
.setAccentColor(COLOR_NOT_TINTED);
|
||||||
if (!isVisible()) {
|
if (!isVisible()) {
|
||||||
|
@@ -66,6 +66,7 @@ public class SettingsPanelActivity extends FragmentActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
getApplicationContext().getTheme().rebase();
|
||||||
createOrUpdatePanel(true /* shouldForceCreation */);
|
createOrUpdatePanel(true /* shouldForceCreation */);
|
||||||
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
||||||
}
|
}
|
||||||
|
@@ -140,8 +140,11 @@ public class SettingsSliceProvider extends SliceProvider {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Map<Uri, SliceData> mSliceWeakDataCache;
|
Map<Uri, SliceData> mSliceWeakDataCache;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
final Map<Uri, SliceBackgroundWorker> mPinnedWorkers = new ArrayMap<>();
|
final Map<Uri, SliceBackgroundWorker> mPinnedWorkers = new ArrayMap<>();
|
||||||
|
|
||||||
|
private boolean mNightMode;
|
||||||
|
|
||||||
public SettingsSliceProvider() {
|
public SettingsSliceProvider() {
|
||||||
super(READ_SEARCH_INDEXABLES);
|
super(READ_SEARCH_INDEXABLES);
|
||||||
}
|
}
|
||||||
@@ -150,6 +153,8 @@ public class SettingsSliceProvider extends SliceProvider {
|
|||||||
public boolean onCreateSliceProvider() {
|
public boolean onCreateSliceProvider() {
|
||||||
mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext());
|
mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext());
|
||||||
mSliceWeakDataCache = new WeakHashMap<>();
|
mSliceWeakDataCache = new WeakHashMap<>();
|
||||||
|
mNightMode = Utils.isNightMode(getContext());
|
||||||
|
getContext().setTheme(R.style.Theme_SettingsBase);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +206,13 @@ public class SettingsSliceProvider extends SliceProvider {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean nightMode = Utils.isNightMode(getContext());
|
||||||
|
if (mNightMode != nightMode) {
|
||||||
|
Log.d(TAG, "Night mode changed, reload theme");
|
||||||
|
mNightMode = nightMode;
|
||||||
|
getContext().getTheme().rebase();
|
||||||
|
}
|
||||||
|
|
||||||
// Before adding a slice to {@link CustomSliceManager}, please get approval
|
// Before adding a slice to {@link CustomSliceManager}, please get approval
|
||||||
// from the Settings team.
|
// from the Settings team.
|
||||||
if (CustomSliceRegistry.isValidUri(sliceUri)) {
|
if (CustomSliceRegistry.isValidUri(sliceUri)) {
|
||||||
|
@@ -73,8 +73,6 @@ public class SliceBuilderUtils {
|
|||||||
* {@param sliceData} is an inline controller.
|
* {@param sliceData} is an inline controller.
|
||||||
*/
|
*/
|
||||||
public static Slice buildSlice(Context context, SliceData sliceData) {
|
public static Slice buildSlice(Context context, SliceData sliceData) {
|
||||||
// Reload theme for switching dark mode on/off
|
|
||||||
context.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
|
|
||||||
Log.d(TAG, "Creating slice for: " + sliceData.getPreferenceController());
|
Log.d(TAG, "Creating slice for: " + sliceData.getPreferenceController());
|
||||||
final BasePreferenceController controller = getPreferenceController(context, sliceData);
|
final BasePreferenceController controller = getPreferenceController(context, sliceData);
|
||||||
FeatureFactory.getFactory(context).getMetricsFeatureProvider()
|
FeatureFactory.getFactory(context).getMetricsFeatureProvider()
|
||||||
|
@@ -86,9 +86,6 @@ public class WifiSlice implements CustomSliceable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Slice getSlice() {
|
public Slice getSlice() {
|
||||||
// Reload theme for switching dark mode on/off
|
|
||||||
mContext.getTheme().applyStyle(R.style.Theme_Settings_Home, true /* force */);
|
|
||||||
|
|
||||||
final boolean isWifiEnabled = isWifiEnabled();
|
final boolean isWifiEnabled = isWifiEnabled();
|
||||||
ListBuilder listBuilder = getListBuilder(isWifiEnabled, null /* accessPoint */);
|
ListBuilder listBuilder = getListBuilder(isWifiEnabled, null /* accessPoint */);
|
||||||
if (!isWifiEnabled) {
|
if (!isWifiEnabled) {
|
||||||
|
@@ -20,6 +20,8 @@ package com.android.settings.slices;
|
|||||||
import static android.content.ContentResolver.SCHEME_CONTENT;
|
import static android.content.ContentResolver.SCHEME_CONTENT;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_DENIED;
|
import static android.content.pm.PackageManager.PERMISSION_DENIED;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static android.content.res.Configuration.UI_MODE_NIGHT_NO;
|
||||||
|
import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -39,6 +41,7 @@ import android.app.slice.SliceManager;
|
|||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.res.Resources.Theme;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -96,7 +99,8 @@ import java.util.Set;
|
|||||||
@Config(shadows = {ShadowUserManager.class, ShadowUtils.class,
|
@Config(shadows = {ShadowUserManager.class, ShadowUtils.class,
|
||||||
SlicesDatabaseAccessorTest.ShadowApplicationPackageManager.class,
|
SlicesDatabaseAccessorTest.ShadowApplicationPackageManager.class,
|
||||||
ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class,
|
ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class,
|
||||||
SettingsSliceProviderTest.ShadowWifiScanWorker.class})
|
SettingsSliceProviderTest.ShadowWifiScanWorker.class,
|
||||||
|
SettingsSliceProviderTest.ShadowTheme.class})
|
||||||
public class SettingsSliceProviderTest {
|
public class SettingsSliceProviderTest {
|
||||||
|
|
||||||
private static final String KEY = "KEY";
|
private static final String KEY = "KEY";
|
||||||
@@ -162,6 +166,7 @@ public class SettingsSliceProviderTest {
|
|||||||
@After
|
@After
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
ShadowThreadUtils.reset();
|
ShadowThreadUtils.reset();
|
||||||
|
ShadowTheme.reset();
|
||||||
DatabaseTestUtils.clearDb(mContext);
|
DatabaseTestUtils.clearDb(mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,6 +268,28 @@ public class SettingsSliceProviderTest {
|
|||||||
assertThat(slice).isNull();
|
assertThat(slice).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindSlice_nightModeChanged_shouldReloadTheme() {
|
||||||
|
mContext.getResources().getConfiguration().uiMode = UI_MODE_NIGHT_YES;
|
||||||
|
|
||||||
|
final SliceData data = getDummyData();
|
||||||
|
mProvider.mSliceWeakDataCache.put(data.getUri(), data);
|
||||||
|
mProvider.onBindSlice(data.getUri());
|
||||||
|
|
||||||
|
assertThat(ShadowTheme.isThemeRebased()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindSlice_nightModeNotChanged_shouldNotReloadTheme() {
|
||||||
|
mContext.getResources().getConfiguration().uiMode = UI_MODE_NIGHT_NO;
|
||||||
|
|
||||||
|
SliceData data = getDummyData();
|
||||||
|
mProvider.mSliceWeakDataCache.put(data.getUri(), data);
|
||||||
|
mProvider.onBindSlice(data.getUri());
|
||||||
|
|
||||||
|
assertThat(ShadowTheme.isThemeRebased()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDescendantUris_fullActionUri_returnsSelf() {
|
public void getDescendantUris_fullActionUri_returnsSelf() {
|
||||||
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(ACTION_SLICE_URI);
|
final Collection<Uri> descendants = mProvider.onGetSliceDescendants(ACTION_SLICE_URI);
|
||||||
@@ -722,4 +749,23 @@ public class SettingsSliceProviderTest {
|
|||||||
return sSetThreadPolicyCount != 0;
|
return sSetThreadPolicyCount != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Implements(Theme.class)
|
||||||
|
public static class ShadowTheme {
|
||||||
|
private static boolean sThemeRebased;
|
||||||
|
|
||||||
|
@Resetter
|
||||||
|
public static void reset() {
|
||||||
|
sThemeRebased = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public void rebase() {
|
||||||
|
sThemeRebased = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isThemeRebased() {
|
||||||
|
return sThemeRebased;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -137,16 +137,19 @@ public class SliceTester {
|
|||||||
*/
|
*/
|
||||||
public static void testSettingsSliderSlice(Context context, Slice slice, SliceData sliceData) {
|
public static void testSettingsSliderSlice(Context context, Slice slice, SliceData sliceData) {
|
||||||
final SliceMetadata metadata = SliceMetadata.from(context, slice);
|
final SliceMetadata metadata = SliceMetadata.from(context, slice);
|
||||||
|
|
||||||
final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
|
|
||||||
final int color = colorItem.getInt();
|
|
||||||
assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
|
|
||||||
|
|
||||||
final SliceAction primaryAction = metadata.getPrimaryAction();
|
final SliceAction primaryAction = metadata.getPrimaryAction();
|
||||||
|
|
||||||
final IconCompat expectedIcon = IconCompat.createWithResource(context,
|
final IconCompat icon = primaryAction.getIcon();
|
||||||
sliceData.getIconResource());
|
if (icon == null) {
|
||||||
assertThat(expectedIcon.toString()).isEqualTo(primaryAction.getIcon().toString());
|
final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
|
||||||
|
final int color = colorItem.getInt();
|
||||||
|
assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
final IconCompat expectedIcon = IconCompat.createWithResource(context,
|
||||||
|
sliceData.getIconResource());
|
||||||
|
assertThat(expectedIcon.toString()).isEqualTo(icon.toString());
|
||||||
|
}
|
||||||
|
|
||||||
final long sliceTTL = metadata.getExpiry();
|
final long sliceTTL = metadata.getExpiry();
|
||||||
assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
|
assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY);
|
||||||
|
Reference in New Issue
Block a user