Merge "[Night] Add a new night theme trigger: bedtime"
This commit is contained in:
@@ -919,15 +919,21 @@ package android.app {
|
||||
method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public void addOnProjectionStateChangedListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.app.UiModeManager.OnProjectionStateChangedListener);
|
||||
method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
|
||||
method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public int getActiveProjectionTypes();
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE) public int getNightModeCustomType();
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public java.util.Set<java.lang.String> getProjectingPackages(int);
|
||||
method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean releaseProjection(int);
|
||||
method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public void removeOnProjectionStateChangedListener(@NonNull android.app.UiModeManager.OnProjectionStateChangedListener);
|
||||
method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean requestProjection(int);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE) public boolean setNightModeActivatedForCustomMode(int, boolean);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE) public void setNightModeCustomType(int);
|
||||
field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
|
||||
field public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = "android.app.action.EXIT_CAR_MODE_PRIORITIZED";
|
||||
field public static final int DEFAULT_PRIORITY = 0; // 0x0
|
||||
field public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE";
|
||||
field public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY";
|
||||
field public static final int MODE_NIGHT_CUSTOM_TYPE_BEDTIME = 1; // 0x1
|
||||
field public static final int MODE_NIGHT_CUSTOM_TYPE_SCHEDULE = 0; // 0x0
|
||||
field public static final int MODE_NIGHT_CUSTOM_TYPE_UNKNOWN = -1; // 0xffffffff
|
||||
field public static final int PROJECTION_TYPE_ALL = -1; // 0xffffffff
|
||||
field public static final int PROJECTION_TYPE_AUTOMOTIVE = 1; // 0x1
|
||||
field public static final int PROJECTION_TYPE_NONE = 0; // 0x0
|
||||
|
||||
@@ -48,19 +48,42 @@ interface IUiModeManager {
|
||||
|
||||
/**
|
||||
* Sets the night mode.
|
||||
* <p>
|
||||
* The mode can be one of:
|
||||
* 1 - notnight mode
|
||||
* 2 - night mode
|
||||
* 3 - automatic mode switching
|
||||
* <ol>notnight mode</ol>
|
||||
* <ol>night mode</ol>
|
||||
* <ol>custom schedule mode switching</ol>
|
||||
*/
|
||||
void setNightMode(int mode);
|
||||
|
||||
/**
|
||||
* Gets the currently configured night mode. Return 1 for notnight,
|
||||
* 2 for night, and 3 for automatic mode switching.
|
||||
* Gets the currently configured night mode.
|
||||
* <p>
|
||||
* Returns
|
||||
* <ol>notnight mode</ol>
|
||||
* <ol>night mode</ol>
|
||||
* <ol>custom schedule mode switching</ol>
|
||||
*/
|
||||
int getNightMode();
|
||||
|
||||
/**
|
||||
* Sets the current night mode to {@link #MODE_NIGHT_CUSTOM} with the custom night mode type
|
||||
* {@code nightModeCustomType}.
|
||||
*
|
||||
* @param nightModeCustomType
|
||||
* @hide
|
||||
*/
|
||||
void setNightModeCustomType(int nightModeCustomType);
|
||||
|
||||
/**
|
||||
* Returns the custom night mode type.
|
||||
* <p>
|
||||
* If the current night mode is not {@link #MODE_NIGHT_CUSTOM}, returns
|
||||
* {@link #MODE_NIGHT_CUSTOM_TYPE_UNKNOWN}.
|
||||
* @hide
|
||||
*/
|
||||
int getNightModeCustomType();
|
||||
|
||||
/**
|
||||
* Sets the dark mode for the given application. This setting is persisted and will override the
|
||||
* system configuration for this application.
|
||||
@@ -81,8 +104,21 @@ interface IUiModeManager {
|
||||
boolean isNightModeLocked();
|
||||
|
||||
/**
|
||||
* [De]Activates night mode
|
||||
*/
|
||||
* [De]activating night mode for the current user if the current night mode is custom and the
|
||||
* custom type matches {@code nightModeCustomType}.
|
||||
*
|
||||
* @param nightModeCustomType the specify type of custom mode
|
||||
* @param active {@code true} to activate night mode. Otherwise, deactivate night mode
|
||||
* @return {@code true} if night mode has successfully activated for the requested
|
||||
* {@code nightModeCustomType}.
|
||||
* @hide
|
||||
*/
|
||||
boolean setNightModeActivatedForCustomMode(int nightModeCustom, boolean active);
|
||||
|
||||
/**
|
||||
* [De]Activates night mode.
|
||||
* @hide
|
||||
*/
|
||||
boolean setNightModeActivated(boolean active);
|
||||
|
||||
/**
|
||||
|
||||
@@ -243,6 +243,45 @@ public class UiModeManager {
|
||||
*/
|
||||
public static final int MODE_NIGHT_YES = 2;
|
||||
|
||||
/**
|
||||
* Granular types for {@link MODE_NIGHT_CUSTOM_TYPE_BEDTIME}
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = { "MODE_NIGHT_CUSTOM_TYPE_" }, value = {
|
||||
MODE_NIGHT_CUSTOM_TYPE_UNKNOWN,
|
||||
MODE_NIGHT_CUSTOM_TYPE_SCHEDULE,
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface NightModeCustomType {}
|
||||
|
||||
/**
|
||||
* A granular type for {@link #MODE_NIGHT_CUSTOM} which is unknown.
|
||||
* <p>
|
||||
* This is the default value when the night mode is set to value other than
|
||||
* {@link #MODE_NIGHT_CUSTOM}.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int MODE_NIGHT_CUSTOM_TYPE_UNKNOWN = -1;
|
||||
|
||||
/**
|
||||
* A granular type for {@link #MODE_NIGHT_CUSTOM} which is based on a custom schedule.
|
||||
* <p>
|
||||
* This is the default value when night mode is set to {@link #MODE_NIGHT_CUSTOM} unless the
|
||||
* the night mode custom type is specified by calling {@link #setNightModeCustomType(int)}.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int MODE_NIGHT_CUSTOM_TYPE_SCHEDULE = 0;
|
||||
|
||||
/**
|
||||
* A granular type for {@link #MODE_NIGHT_CUSTOM} which is based on the bedtime schedule.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int MODE_NIGHT_CUSTOM_TYPE_BEDTIME = 1;
|
||||
|
||||
private IUiModeManager mService;
|
||||
|
||||
/**
|
||||
@@ -495,6 +534,45 @@ public class UiModeManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current night mode to {@link #MODE_NIGHT_CUSTOM} with the custom night mode type
|
||||
* {@code nightModeCustomType}.
|
||||
*
|
||||
* @param nightModeCustomType
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
|
||||
public void setNightModeCustomType(@NightModeCustomType int nightModeCustomType) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
mService.setNightModeCustomType(nightModeCustomType);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the custom night mode type.
|
||||
* <p>
|
||||
* If the current night mode is not {@link #MODE_NIGHT_CUSTOM}, returns
|
||||
* {@link #MODE_NIGHT_CUSTOM_TYPE_UNKNOWN}.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
|
||||
public int getNightModeCustomType() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getNightModeCustomType();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
return MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and persist the night mode for this application.
|
||||
* <p>
|
||||
@@ -598,12 +676,37 @@ public class UiModeManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* [De]activating night mode for the current user if the current night mode is custom and the
|
||||
* custom type matches {@code nightModeCustomType}.
|
||||
*
|
||||
* @param nightModeCustomType the specify type of custom mode
|
||||
* @param active {@code true} to activate night mode. Otherwise, deactivate night mode
|
||||
* @return {@code true} if night mode has successfully activated for the requested
|
||||
* {@code nightModeCustomType}.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
|
||||
public boolean setNightModeActivatedForCustomMode(@NightModeCustomType int nightModeCustomType,
|
||||
boolean active) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.setNightModeActivatedForCustomMode(nightModeCustomType, active);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activating night mode for the current user
|
||||
*
|
||||
* @return {@code true} if the change is successful
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
|
||||
public boolean setNightModeActivated(boolean active) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
|
||||
@@ -8983,6 +8983,15 @@ public final class Settings {
|
||||
@Readable
|
||||
public static final String UI_NIGHT_MODE = "ui_night_mode";
|
||||
|
||||
/**
|
||||
* The current night mode custom type that has been selected by the user. Owned
|
||||
* and controlled by UiModeManagerService. Constants are as per UiModeManager.
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
@SuppressLint("NoSettingsProvider")
|
||||
public static final String UI_NIGHT_MODE_CUSTOM_TYPE = "ui_night_mode_custom_type";
|
||||
|
||||
/**
|
||||
* The current night mode that has been overridden to turn on by the system. Owned
|
||||
* and controlled by UiModeManagerService. Constants are as per
|
||||
|
||||
@@ -19,6 +19,9 @@ package com.android.server;
|
||||
import static android.app.UiModeManager.DEFAULT_PRIORITY;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_AUTO;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_NO;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_YES;
|
||||
import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
|
||||
@@ -40,6 +43,7 @@ import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.StatusBarManager;
|
||||
import android.app.UiModeManager;
|
||||
import android.app.UiModeManager.NightModeCustomType;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -115,6 +119,7 @@ final class UiModeManagerService extends SystemService {
|
||||
|
||||
private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
|
||||
private int mNightMode = UiModeManager.MODE_NIGHT_NO;
|
||||
private int mNightModeCustomType = UiModeManager.MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
|
||||
private final LocalTime DEFAULT_CUSTOM_NIGHT_START_TIME = LocalTime.of(22, 0);
|
||||
private final LocalTime DEFAULT_CUSTOM_NIGHT_END_TIME = LocalTime.of(6, 0);
|
||||
private LocalTime mCustomAutoNightModeStartMilliseconds = DEFAULT_CUSTOM_NIGHT_START_TIME;
|
||||
@@ -136,6 +141,7 @@ final class UiModeManagerService extends SystemService {
|
||||
private boolean mWatch;
|
||||
private boolean mVrHeadset;
|
||||
private boolean mComputedNightMode;
|
||||
private boolean mLastBedtimeRequestedNightMode = false;
|
||||
private int mCarModeEnableFlags;
|
||||
private boolean mSetupWizardComplete;
|
||||
|
||||
@@ -541,7 +547,9 @@ final class UiModeManagerService extends SystemService {
|
||||
mNightMode = Secure.getIntForUser(context.getContentResolver(),
|
||||
Secure.UI_NIGHT_MODE, res.getInteger(
|
||||
com.android.internal.R.integer.config_defaultNightMode), userId);
|
||||
mOverrideNightModeOn = Secure.getIntForUser(context.getContentResolver(),
|
||||
mNightModeCustomType = Secure.getIntForUser(context.getContentResolver(),
|
||||
Secure.UI_NIGHT_MODE_CUSTOM_TYPE, MODE_NIGHT_CUSTOM_TYPE_UNKNOWN, userId);
|
||||
mOverrideNightModeOn = Secure.getIntForUser(context.getContentResolver(),
|
||||
Secure.UI_NIGHT_MODE_OVERRIDE_ON, 0, userId) != 0;
|
||||
mOverrideNightModeOff = Secure.getIntForUser(context.getContentResolver(),
|
||||
Secure.UI_NIGHT_MODE_OVERRIDE_OFF, 0, userId) != 0;
|
||||
@@ -702,6 +710,14 @@ final class UiModeManagerService extends SystemService {
|
||||
|
||||
@Override
|
||||
public void setNightMode(int mode) {
|
||||
// MODE_NIGHT_CUSTOM_TYPE_SCHEDULE is the default for MODE_NIGHT_CUSTOM.
|
||||
int customModeType = mode == MODE_NIGHT_CUSTOM
|
||||
? MODE_NIGHT_CUSTOM_TYPE_SCHEDULE
|
||||
: MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
|
||||
setNightModeInternal(mode, customModeType);
|
||||
}
|
||||
|
||||
private void setNightModeInternal(int mode, int customModeType) {
|
||||
if (isNightModeLocked() && (getContext().checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
|
||||
!= PackageManager.PERMISSION_GRANTED)) {
|
||||
@@ -722,12 +738,14 @@ final class UiModeManagerService extends SystemService {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
if (mNightMode != mode) {
|
||||
if (mNightMode != mode || mNightModeCustomType != customModeType) {
|
||||
if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) {
|
||||
unregisterScreenOffEventLocked();
|
||||
cancelCustomAlarm();
|
||||
}
|
||||
|
||||
mNightModeCustomType = mode == MODE_NIGHT_CUSTOM
|
||||
? customModeType
|
||||
: MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
|
||||
mNightMode = mode;
|
||||
resetNightModeOverrideLocked();
|
||||
persistNightMode(user);
|
||||
@@ -753,6 +771,30 @@ final class UiModeManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNightModeCustomType(@NightModeCustomType int nightModeCustomType) {
|
||||
if (getContext().checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException(
|
||||
"setNightModeCustomType requires MODIFY_DAY_NIGHT_MODE permission");
|
||||
}
|
||||
setNightModeInternal(MODE_NIGHT_CUSTOM, nightModeCustomType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNightModeCustomType() {
|
||||
if (getContext().checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException(
|
||||
"getNightModeCustomType requires MODIFY_DAY_NIGHT_MODE permission");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
return mNightModeCustomType;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationNightMode(@UiModeManager.NightMode int mode) {
|
||||
switch (mode) {
|
||||
@@ -807,11 +849,20 @@ final class UiModeManagerService extends SystemService {
|
||||
dumpImpl(pw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setNightModeActivatedForCustomMode(int modeNightCustomType, boolean active) {
|
||||
return setNightModeActivatedForModeInternal(modeNightCustomType, active);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setNightModeActivated(boolean active) {
|
||||
if (isNightModeLocked() && (getContext().checkCallingOrSelfPermission(
|
||||
return setNightModeActivatedForModeInternal(mNightModeCustomType, active);
|
||||
}
|
||||
|
||||
private boolean setNightModeActivatedForModeInternal(int modeCustomType, boolean active) {
|
||||
if (getContext().checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
|
||||
!= PackageManager.PERMISSION_GRANTED)) {
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
Slog.e(TAG, "Night mode locked, requires MODIFY_DAY_NIGHT_MODE permission");
|
||||
return false;
|
||||
}
|
||||
@@ -824,6 +875,14 @@ final class UiModeManagerService extends SystemService {
|
||||
return false;
|
||||
|
||||
}
|
||||
// Store the last requested bedtime night mode state so that we don't need to notify
|
||||
// anyone if the user decides to switch to the night mode to bedtime.
|
||||
if (modeCustomType == MODE_NIGHT_CUSTOM_TYPE_BEDTIME) {
|
||||
mLastBedtimeRequestedNightMode = active;
|
||||
}
|
||||
if (modeCustomType != mNightModeCustomType) {
|
||||
return false;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -1421,6 +1480,8 @@ final class UiModeManagerService extends SystemService {
|
||||
if (mCarModeEnabled || mCar) return;
|
||||
Secure.putIntForUser(getContext().getContentResolver(),
|
||||
Secure.UI_NIGHT_MODE, mNightMode, user);
|
||||
Secure.putLongForUser(getContext().getContentResolver(),
|
||||
Secure.UI_NIGHT_MODE_CUSTOM_TYPE, mNightModeCustomType, user);
|
||||
Secure.putLongForUser(getContext().getContentResolver(),
|
||||
Secure.DARK_THEME_CUSTOM_START_TIME,
|
||||
mCustomAutoNightModeStartMilliseconds.toNanoOfDay() / 1000, user);
|
||||
@@ -1473,10 +1534,14 @@ final class UiModeManagerService extends SystemService {
|
||||
}
|
||||
|
||||
if (mNightMode == MODE_NIGHT_CUSTOM) {
|
||||
registerTimeChangeEvent();
|
||||
final boolean activate = computeCustomNightMode();
|
||||
updateComputedNightModeLocked(activate);
|
||||
scheduleNextCustomTimeListener();
|
||||
if (mNightModeCustomType == MODE_NIGHT_CUSTOM_TYPE_BEDTIME) {
|
||||
updateComputedNightModeLocked(mLastBedtimeRequestedNightMode);
|
||||
} else {
|
||||
registerTimeChangeEvent();
|
||||
final boolean activate = computeCustomNightMode();
|
||||
updateComputedNightModeLocked(activate);
|
||||
scheduleNextCustomTimeListener();
|
||||
}
|
||||
} else {
|
||||
unregisterTimeChangeEvent();
|
||||
}
|
||||
@@ -1494,6 +1559,7 @@ final class UiModeManagerService extends SystemService {
|
||||
"updateConfigurationLocked: mDockState=" + mDockState
|
||||
+ "; mCarMode=" + mCarModeEnabled
|
||||
+ "; mNightMode=" + mNightMode
|
||||
+ "; mNightModeCustomType=" + mNightModeCustomType
|
||||
+ "; uiMode=" + uiMode);
|
||||
}
|
||||
|
||||
@@ -1534,7 +1600,8 @@ final class UiModeManagerService extends SystemService {
|
||||
}
|
||||
|
||||
private boolean shouldApplyAutomaticChangesImmediately() {
|
||||
return mCar || !mPowerManager.isInteractive();
|
||||
return mCar || !mPowerManager.isInteractive()
|
||||
|| mNightModeCustomType == MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
|
||||
}
|
||||
|
||||
private void scheduleNextCustomTimeListener() {
|
||||
|
||||
@@ -16,14 +16,20 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import static android.Manifest.permission.MODIFY_DAY_NIGHT_MODE;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_AUTO;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_NO;
|
||||
import static android.app.UiModeManager.MODE_NIGHT_YES;
|
||||
import static android.app.UiModeManager.PROJECTION_TYPE_ALL;
|
||||
import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
|
||||
import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
@@ -194,7 +200,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Ignore // b/152719290 - Fails on stage-aosp-master
|
||||
@Test
|
||||
public void setNightMoveActivated_overridesFunctionCorrectly() throws RemoteException {
|
||||
public void setNightModeActivated_overridesFunctionCorrectly() throws RemoteException {
|
||||
// set up
|
||||
when(mPowerManager.isInteractive()).thenReturn(false);
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
@@ -224,6 +230,29 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
|
||||
assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivated_true_withCustomModeBedtime_shouldOverrideNightModeCorrectly()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
|
||||
|
||||
mService.setNightModeActivated(true);
|
||||
|
||||
assertThat(mUiManagerService.getConfiguration().isNightModeActive()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivated_false_withCustomModeBedtime_shouldOverrideNightModeCorrectly()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
|
||||
|
||||
mService.setNightModeActivated(true);
|
||||
mService.setNightModeActivated(false);
|
||||
|
||||
assertThat(mUiManagerService.getConfiguration().isNightModeActive()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAutoMode_screenOffRegistered() throws RemoteException {
|
||||
try {
|
||||
@@ -247,7 +276,44 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivated_fromNoToYesAndBAck() throws RemoteException {
|
||||
public void setNightModeCustomType_bedtime_shouldNotActivateNightMode() throws RemoteException {
|
||||
try {
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeCustomType_noPermission_shouldThrow() throws RemoteException {
|
||||
when(mContext.checkCallingOrSelfPermission(eq(MODIFY_DAY_NIGHT_MODE)))
|
||||
.thenReturn(PackageManager.PERMISSION_DENIED);
|
||||
|
||||
assertThrows(SecurityException.class,
|
||||
() -> mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeCustomType_bedtime_shouldHaveNoScreenOffRegistered()
|
||||
throws RemoteException {
|
||||
try {
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
ArgumentCaptor<IntentFilter> intentFiltersCaptor = ArgumentCaptor.forClass(
|
||||
IntentFilter.class);
|
||||
verify(mContext, atLeastOnce()).registerReceiver(any(BroadcastReceiver.class),
|
||||
intentFiltersCaptor.capture());
|
||||
|
||||
List<IntentFilter> intentFilters = intentFiltersCaptor.getAllValues();
|
||||
for (IntentFilter intentFilter : intentFilters) {
|
||||
assertThat(intentFilter.hasAction(Intent.ACTION_SCREEN_OFF)).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivated_fromNoToYesAndBack() throws RemoteException {
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
mService.setNightModeActivated(true);
|
||||
assertTrue(isNightModeActivated());
|
||||
@@ -256,7 +322,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivated_permissiontoChangeOtherUsers() throws RemoteException {
|
||||
public void setNightModeActivated_permissionToChangeOtherUsers() throws RemoteException {
|
||||
SystemService.TargetUser user = mock(SystemService.TargetUser.class);
|
||||
doReturn(9).when(user).getUserIdentifier();
|
||||
mUiManagerService.onUserSwitching(user, user);
|
||||
@@ -266,6 +332,89 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
|
||||
assertFalse(mService.setNightModeActivated(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_shouldActivate()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOffAndBedtime_shouldDeactivate()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndSchedule_shouldNotActivate()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_SCHEDULE, true /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivatedForCustomMode_customTypeSchedule_withParamOnAndBedtime_shouldNotActivate()
|
||||
throws RemoteException {
|
||||
mService.setNightMode(MODE_NIGHT_CUSTOM);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivatedForCustomMode_customTypeSchedule_withParamOnAndBedtime_thenCustomTypeBedtime_shouldActivate()
|
||||
throws RemoteException {
|
||||
mService.setNightMode(MODE_NIGHT_CUSTOM);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_thenCustomTypeSchedule_shouldKeepNightModeActivate()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
mService.setNightMode(MODE_NIGHT_CUSTOM);
|
||||
LocalTime now = LocalTime.now();
|
||||
mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
|
||||
mService.setCustomNightModeEnd(now.plusHours(2L).toNanoOfDay() / 1000);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setNightModeActivatedForCustomMode_customTypeBedtime_withParamOnAndBedtime_thenCustomTypeScheduleAndScreenOff_shouldDeactivateNightMode()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
mService.setNightMode(MODE_NIGHT_CUSTOM);
|
||||
LocalTime now = LocalTime.now();
|
||||
mService.setCustomNightModeStart(now.plusHours(1L).toNanoOfDay() / 1000);
|
||||
mService.setCustomNightModeEnd(now.plusHours(2L).toNanoOfDay() / 1000);
|
||||
mScreenOffCallback.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void autoNightModeSwitch_batterySaverOn() throws RemoteException {
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
@@ -282,6 +431,191 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
|
||||
assertTrue(isNightModeActivated());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeCustomBedtime_batterySaverOn_notInBedtime_shouldActivateNightMode()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
|
||||
mPowerSaveConsumer.accept(
|
||||
new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeCustomBedtime_batterySaverOn_afterBedtime_shouldKeepNightModeActivated()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mPowerSaveConsumer.accept(
|
||||
new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
|
||||
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeBedtime_duringBedtime_batterySaverOnThenOff_shouldKeepNightModeActivated()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
mPowerSaveConsumer.accept(
|
||||
new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
|
||||
mPowerSaveConsumer.accept(
|
||||
new PowerSaveState.Builder().setBatterySaverEnabled(false).build());
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeCustomBedtime_duringBedtime_batterySaverOnThenOff_finallyAfterBedtime_shouldDeactivateNightMode()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
mPowerSaveConsumer.accept(
|
||||
new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
|
||||
mPowerSaveConsumer.accept(
|
||||
new PowerSaveState.Builder().setBatterySaverEnabled(false).build());
|
||||
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeCustomBedtime_duringBedtime_changeModeToNo_shouldDeactivateNightMode()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeCustomBedtime_duringBedtime_changeModeToNoAndThenExitBedtime_shouldKeepNightModeDeactivated()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeCustomBedtime_duringBedtime_changeModeToYes_shouldKeepNightModeActivated()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
mService.setNightMode(MODE_NIGHT_YES);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeCustomBedtime_duringBedtime_changeModeToYesAndThenExitBedtime_shouldKeepNightModeActivated()
|
||||
throws RemoteException {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
mService.setNightMode(MODE_NIGHT_YES);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, false /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeNo_duringBedtime_shouldKeepNightModeDeactivated()
|
||||
throws RemoteException {
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeNo_thenChangeToCustomTypeBedtimeAndActivate_shouldActivateNightMode()
|
||||
throws RemoteException {
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeYes_thenChangeToCustomTypeBedtime_shouldDeactivateNightMode()
|
||||
throws RemoteException {
|
||||
mService.setNightMode(MODE_NIGHT_YES);
|
||||
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeYes_thenChangeToCustomTypeBedtimeAndActivate_shouldActivateNightMode()
|
||||
throws RemoteException {
|
||||
mService.setNightMode(MODE_NIGHT_YES);
|
||||
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeAuto_thenChangeToCustomTypeBedtime_notInBedtime_shouldDeactivateNightMode()
|
||||
throws RemoteException {
|
||||
// set mode to auto
|
||||
mService.setNightMode(MODE_NIGHT_AUTO);
|
||||
mService.setNightModeActivated(true);
|
||||
// now it is night time
|
||||
doReturn(true).when(mTwilightState).isNight();
|
||||
mTwilightListener.onTwilightStateChanged(mTwilightState);
|
||||
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
|
||||
assertThat(isNightModeActivated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nightModeAuto_thenChangeToCustomTypeBedtime_duringBedtime_shouldActivateNightMode()
|
||||
throws RemoteException {
|
||||
// set mode to auto
|
||||
mService.setNightMode(MODE_NIGHT_AUTO);
|
||||
mService.setNightModeActivated(true);
|
||||
// now it is night time
|
||||
doReturn(true).when(mTwilightState).isNight();
|
||||
mTwilightListener.onTwilightStateChanged(mTwilightState);
|
||||
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
mService.setNightModeActivatedForCustomMode(
|
||||
MODE_NIGHT_CUSTOM_TYPE_BEDTIME, true /* active */);
|
||||
|
||||
assertThat(isNightModeActivated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAutoMode_clearCache() throws RemoteException {
|
||||
try {
|
||||
@@ -326,6 +660,62 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
|
||||
assertEquals(MODE_NIGHT_AUTO, mService.getNightMode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNightModeCustomType_nightModeNo_shouldReturnUnknown() throws RemoteException {
|
||||
try {
|
||||
mService.setNightMode(MODE_NIGHT_NO);
|
||||
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
|
||||
|
||||
assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNightModeCustomType_nightModeYes_shouldReturnUnknown() throws RemoteException {
|
||||
try {
|
||||
mService.setNightMode(MODE_NIGHT_YES);
|
||||
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
|
||||
|
||||
assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNightModeCustomType_nightModeAuto_shouldReturnUnknown() throws RemoteException {
|
||||
try {
|
||||
mService.setNightMode(MODE_NIGHT_AUTO);
|
||||
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
|
||||
|
||||
assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNightModeCustomType_nightModeCustom_shouldReturnSchedule()
|
||||
throws RemoteException {
|
||||
try {
|
||||
mService.setNightMode(MODE_NIGHT_CUSTOM);
|
||||
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
|
||||
|
||||
assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_SCHEDULE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNightModeCustomType_nightModeCustomBedtime_shouldReturnBedtime()
|
||||
throws RemoteException {
|
||||
try {
|
||||
mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
} catch (SecurityException e) { /* we should ignore this update config exception*/ }
|
||||
|
||||
assertThat(mService.getNightModeCustomType()).isEqualTo(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNightModeCustomType_permissionNotGranted_shouldThrow()
|
||||
throws RemoteException {
|
||||
when(mContext.checkCallingOrSelfPermission(eq(MODIFY_DAY_NIGHT_MODE)))
|
||||
.thenReturn(PackageManager.PERMISSION_DENIED);
|
||||
|
||||
assertThrows(SecurityException.class, () -> mService.getNightModeCustomType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNightModeActive_nightModeYes() throws RemoteException {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user