Merge "Letterbox Reachability: Add a central stop for repositioning." into sc-v2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
475584bd10
@@ -4915,16 +4915,15 @@
|
||||
device orientation. -->
|
||||
<bool name="config_letterboxIsReachabilityEnabled">false</bool>
|
||||
|
||||
<!-- Default horizonal position of a center of the letterboxed app window when reachability is
|
||||
enabled and an app is fullscreen in landscape device orientation.
|
||||
0 corresponds to the left side of the screen and 1 to the right side. If given value < 0.0
|
||||
or > 1, it is ignored and right positionis used (1.0). The position multiplier is changed
|
||||
to a symmetrical value computed as (1 - current multiplier) after each double tap in the
|
||||
letterbox area. -->
|
||||
<item name="config_letterboxDefaultPositionMultiplierForReachability"
|
||||
format="float" type="dimen">
|
||||
0.9
|
||||
</item>
|
||||
<!-- Default horizonal position of the letterboxed app window when reachability is
|
||||
enabled and an app is fullscreen in landscape device orientation. When reachability is
|
||||
enabled, the position can change between left, center and right. This config defines the
|
||||
default one:
|
||||
- Option 0 - Left.
|
||||
- Option 1 - Center.
|
||||
- Option 2 - Right.
|
||||
If given value is outside of this range, the option 1 (center) is assummed. -->
|
||||
<integer name="config_letterboxDefaultPositionForReachability">1</integer>
|
||||
|
||||
<!-- If true, hide the display cutout with display area -->
|
||||
<bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>
|
||||
|
||||
@@ -4262,7 +4262,7 @@
|
||||
<java-symbol type="color" name="config_letterboxBackgroundColor" />
|
||||
<java-symbol type="dimen" name="config_letterboxHorizontalPositionMultiplier" />
|
||||
<java-symbol type="bool" name="config_letterboxIsReachabilityEnabled" />
|
||||
<java-symbol type="dimen" name="config_letterboxDefaultPositionMultiplierForReachability" />
|
||||
<java-symbol type="integer" name="config_letterboxDefaultPositionForReachability" />
|
||||
|
||||
<java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.view.WindowManager;
|
||||
|
||||
import com.android.server.UiThread;
|
||||
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@@ -70,7 +71,7 @@ public class Letterbox {
|
||||
private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow");
|
||||
private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom };
|
||||
// Reachability gestures.
|
||||
private final Runnable mDoubleTapCallback;
|
||||
private final IntConsumer mDoubleTapCallback;
|
||||
|
||||
/**
|
||||
* Constructs a Letterbox.
|
||||
@@ -84,7 +85,7 @@ public class Letterbox {
|
||||
Supplier<Boolean> hasWallpaperBackgroundSupplier,
|
||||
Supplier<Integer> blurRadiusSupplier,
|
||||
Supplier<Float> darkScrimAlphaSupplier,
|
||||
Runnable doubleTapCallback) {
|
||||
IntConsumer doubleTapCallback) {
|
||||
mSurfaceControlFactory = surfaceControlFactory;
|
||||
mTransactionFactory = transactionFactory;
|
||||
mAreCornersRounded = areCornersRounded;
|
||||
@@ -262,7 +263,7 @@ public class Letterbox {
|
||||
@Override
|
||||
public boolean onDoubleTapEvent(MotionEvent e) {
|
||||
if (e.getAction() == MotionEvent.ACTION_UP) {
|
||||
mDoubleTapCallback.run();
|
||||
mDoubleTapCallback.accept((int) e.getX());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -54,6 +54,27 @@ final class LetterboxConfiguration {
|
||||
/** Using wallpaper as a background which can be blurred or dimmed with dark scrim. */
|
||||
static final int LETTERBOX_BACKGROUND_WALLPAPER = 3;
|
||||
|
||||
/**
|
||||
* Enum for Letterbox reachability position types.
|
||||
*
|
||||
* <p>Order from left to right is important since it's used in {@link
|
||||
* #movePositionForReachabilityToNextRightStop} and {@link
|
||||
* #movePositionForReachabilityToNextLeftStop}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({LETTERBOX_REACHABILITY_POSITION_LEFT, LETTERBOX_REACHABILITY_POSITION_CENTER,
|
||||
LETTERBOX_REACHABILITY_POSITION_RIGHT})
|
||||
@interface LetterboxReachabilityPosition {};
|
||||
|
||||
/** Letterboxed app window is aligned to the left side. */
|
||||
static final int LETTERBOX_REACHABILITY_POSITION_LEFT = 0;
|
||||
|
||||
/** Letterboxed app window is positioned in the horizontal center. */
|
||||
static final int LETTERBOX_REACHABILITY_POSITION_CENTER = 1;
|
||||
|
||||
/** Letterboxed app window is aligned to the right side. */
|
||||
static final int LETTERBOX_REACHABILITY_POSITION_RIGHT = 2;
|
||||
|
||||
final Context mContext;
|
||||
|
||||
// Aspect ratio of letterbox for fixed orientation, values <=
|
||||
@@ -85,25 +106,25 @@ final class LetterboxConfiguration {
|
||||
// side of the screen and 1.0 to the right side.
|
||||
private float mLetterboxHorizontalPositionMultiplier;
|
||||
|
||||
// Default horizontal position of a center of the letterboxed app window when reachability is
|
||||
// enabled and an app is fullscreen in landscape device orientatio. 0 corresponds to the left
|
||||
// side of the screen and 1.0 to the right side.
|
||||
// It is used as a starting point for mLetterboxHorizontalMultiplierForReachability.
|
||||
private float mDefaultPositionMultiplierForReachability;
|
||||
// Default horizontal position the letterboxed app window when reachability is enabled and
|
||||
// an app is fullscreen in landscape device orientatio.
|
||||
// It is used as a starting point for mLetterboxPositionForReachability.
|
||||
@LetterboxReachabilityPosition
|
||||
private int mDefaultPositionForReachability;
|
||||
|
||||
// Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
|
||||
// device orientation.
|
||||
private boolean mIsReachabilityEnabled;
|
||||
|
||||
// Horizontal position of a center of the letterboxed app window. 0 corresponds to
|
||||
// the left side of the screen and 1 to the right side. Keep it global to prevent
|
||||
// "jumps" when switching between letterboxed apps. It's updated to reposition the app
|
||||
// window in response to a double tap gesture (see LetterboxUiController#handleDoubleTap).
|
||||
// Used in LetterboxUiController#getHorizontalPositionMultiplier which is called from
|
||||
// Horizontal position of a center of the letterboxed app window which is global to prevent
|
||||
// "jumps" when switching between letterboxed apps. It's updated to reposition the app window
|
||||
// in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
|
||||
// LetterboxUiController#getHorizontalPositionMultiplier which is called from
|
||||
// ActivityRecord#updateResolvedBoundsHorizontalPosition.
|
||||
// TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
|
||||
// Overview after changing position in another app.
|
||||
private volatile float mLetterboxHorizontalMultiplierForReachability;
|
||||
@LetterboxReachabilityPosition
|
||||
private volatile int mLetterboxPositionForReachability;
|
||||
|
||||
LetterboxConfiguration(Context systemUiContext) {
|
||||
mContext = systemUiContext;
|
||||
@@ -120,9 +141,8 @@ final class LetterboxConfiguration {
|
||||
R.dimen.config_letterboxHorizontalPositionMultiplier);
|
||||
mIsReachabilityEnabled = mContext.getResources().getBoolean(
|
||||
R.bool.config_letterboxIsReachabilityEnabled);
|
||||
mDefaultPositionMultiplierForReachability = mContext.getResources().getFloat(
|
||||
R.dimen.config_letterboxDefaultPositionMultiplierForReachability);
|
||||
mLetterboxHorizontalMultiplierForReachability = mDefaultPositionMultiplierForReachability;
|
||||
mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext);
|
||||
mLetterboxPositionForReachability = mDefaultPositionForReachability;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,58 +415,90 @@ final class LetterboxConfiguration {
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets default horizontal position of a center of the letterboxed app window when reachability
|
||||
* is enabled specified in {@link
|
||||
* R.dimen.config_letterboxDefaultPositionMultiplierForReachability} or via an ADB command.
|
||||
* 0 corresponds to the left side of the screen and 1 to the right side. The returned value is
|
||||
* >= 0.0 and <= 1.0.
|
||||
* Gets default horizontal position of the letterboxed app window when reachability is enabled.
|
||||
* Specified in {@link R.integer.config_letterboxDefaultPositionForReachability} or via an ADB
|
||||
* command.
|
||||
*/
|
||||
float getDefaultPositionMultiplierForReachability() {
|
||||
return (mDefaultPositionMultiplierForReachability < 0.0f
|
||||
|| mDefaultPositionMultiplierForReachability > 1.0f)
|
||||
// Default to a right position if invalid value is provided.
|
||||
? 1.0f : mDefaultPositionMultiplierForReachability;
|
||||
@LetterboxReachabilityPosition
|
||||
int getDefaultPositionForReachability() {
|
||||
return mDefaultPositionForReachability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides default horizontal position of a center of the letterboxed app window when
|
||||
* reachability is enabled. If given value < 0.0 or > 1.0, then it and a value of {@link
|
||||
* R.dimen.config_letterboxDefaultPositionMultiplierForReachability} are ignored and the right
|
||||
* position (1.0) is used.
|
||||
* Overrides default horizonal position of the letterboxed app window when reachability
|
||||
* is enabled.
|
||||
*/
|
||||
void setDefaultPositionMultiplierForReachability(float multiplier) {
|
||||
mDefaultPositionMultiplierForReachability = multiplier;
|
||||
void setDefaultPositionForReachability(@LetterboxReachabilityPosition int position) {
|
||||
mDefaultPositionForReachability = position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets default horizontal position of a center of the letterboxed app window when
|
||||
* reachability is enabled to {@link
|
||||
* R.dimen.config_letterboxDefaultPositionMultiplierForReachability}.
|
||||
* Resets default horizontal position of the letterboxed app window when reachability is
|
||||
* enabled to {@link R.integer.config_letterboxDefaultPositionForReachability}.
|
||||
*/
|
||||
void resetDefaultPositionMultiplierForReachability() {
|
||||
mDefaultPositionMultiplierForReachability = mContext.getResources().getFloat(
|
||||
R.dimen.config_letterboxDefaultPositionMultiplierForReachability);
|
||||
void resetDefaultPositionForReachability() {
|
||||
mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext);
|
||||
}
|
||||
|
||||
@LetterboxReachabilityPosition
|
||||
private static int readLetterboxReachabilityPositionFromConfig(Context context) {
|
||||
int position = context.getResources().getInteger(
|
||||
R.integer.config_letterboxDefaultPositionForReachability);
|
||||
return position == LETTERBOX_REACHABILITY_POSITION_LEFT
|
||||
|| position == LETTERBOX_REACHABILITY_POSITION_CENTER
|
||||
|| position == LETTERBOX_REACHABILITY_POSITION_RIGHT
|
||||
? position : LETTERBOX_REACHABILITY_POSITION_CENTER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets horizontal position of a center of the letterboxed app window when reachability
|
||||
* is enabled specified. 0 corresponds to the left side of the screen and 1 to the right side.
|
||||
*
|
||||
* <p>The position multiplier is changed to a symmetrical value computed as (1 - current
|
||||
* multiplier) after each double tap in the letterbox area.
|
||||
* <p>The position multiplier is changed after each double tap in the letterbox area.
|
||||
*/
|
||||
float getHorizontalMultiplierForReachability() {
|
||||
return mLetterboxHorizontalMultiplierForReachability;
|
||||
switch (mLetterboxPositionForReachability) {
|
||||
case LETTERBOX_REACHABILITY_POSITION_LEFT:
|
||||
return 0.0f;
|
||||
case LETTERBOX_REACHABILITY_POSITION_CENTER:
|
||||
return 0.5f;
|
||||
case LETTERBOX_REACHABILITY_POSITION_RIGHT:
|
||||
return 1.0f;
|
||||
default:
|
||||
throw new AssertionError(
|
||||
"Unexpected letterbox position type: " + mLetterboxPositionForReachability);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a string representing the given {@link LetterboxReachabilityPosition}. */
|
||||
static String letterboxReachabilityPositionToString(
|
||||
@LetterboxReachabilityPosition int position) {
|
||||
switch (position) {
|
||||
case LETTERBOX_REACHABILITY_POSITION_LEFT:
|
||||
return "LETTERBOX_REACHABILITY_POSITION_LEFT";
|
||||
case LETTERBOX_REACHABILITY_POSITION_CENTER:
|
||||
return "LETTERBOX_REACHABILITY_POSITION_CENTER";
|
||||
case LETTERBOX_REACHABILITY_POSITION_RIGHT:
|
||||
return "LETTERBOX_REACHABILITY_POSITION_RIGHT";
|
||||
default:
|
||||
throw new AssertionError(
|
||||
"Unexpected letterbox position type: " + position);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes horizontal position of a center of the letterboxed app window to the opposite
|
||||
* (1 - current multiplier) when reachability is enabled specified. 0 corresponds to the left
|
||||
* side of the screen and 1 to the right side.
|
||||
* Changes letterbox position for reachability to the next available one on the right side.
|
||||
*/
|
||||
void flipHorizontalMultiplierForReachability() {
|
||||
mLetterboxHorizontalMultiplierForReachability =
|
||||
1.0f - mLetterboxHorizontalMultiplierForReachability;
|
||||
void movePositionForReachabilityToNextRightStop() {
|
||||
mLetterboxPositionForReachability = Math.min(
|
||||
mLetterboxPositionForReachability + 1, LETTERBOX_REACHABILITY_POSITION_RIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes letterbox position for reachability to the next available one on the left side.
|
||||
*/
|
||||
void movePositionForReachabilityToNextLeftStop() {
|
||||
mLetterboxPositionForReachability = Math.max(mLetterboxPositionForReachability - 1, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -210,12 +210,23 @@ final class LetterboxUiController {
|
||||
return mActivityRecord.mWmService.mContext.getResources();
|
||||
}
|
||||
|
||||
private void handleDoubleTap() {
|
||||
private void handleDoubleTap(int x) {
|
||||
if (!isReachabilityEnabled() || mActivityRecord.isInTransition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mLetterboxConfiguration.flipHorizontalMultiplierForReachability();
|
||||
if (mLetterbox.getInnerFrame().left <= x && mLetterbox.getInnerFrame().right >= x) {
|
||||
// Only react to clicks at the sides of the letterboxed app window.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLetterbox.getInnerFrame().left > x) {
|
||||
// Moving to the next stop on the left side of the app window: right > center > left.
|
||||
mLetterboxConfiguration.movePositionForReachabilityToNextLeftStop();
|
||||
} else if (mLetterbox.getInnerFrame().right < x) {
|
||||
// Moving to the next stop on the right side of the app window: left > center > right.
|
||||
mLetterboxConfiguration.movePositionForReachabilityToNextRightStop();
|
||||
}
|
||||
|
||||
// TODO(197549949): Add animation for transition.
|
||||
mActivityRecord.recomputeConfiguration();
|
||||
|
||||
@@ -23,6 +23,9 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_
|
||||
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
|
||||
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR;
|
||||
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER;
|
||||
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_CENTER;
|
||||
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_LEFT;
|
||||
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_RIGHT;
|
||||
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.graphics.Color;
|
||||
@@ -44,6 +47,7 @@ import com.android.internal.protolog.ProtoLogImpl;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
|
||||
import com.android.server.wm.LetterboxConfiguration.LetterboxReachabilityPosition;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
@@ -787,22 +791,33 @@ public class WindowManagerShellCommand extends ShellCommand {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runSetLetterboxDefaultPositionMultiplierForReachability(PrintWriter pw)
|
||||
private int runSetLetterboxDefaultPositionForReachability(PrintWriter pw)
|
||||
throws RemoteException {
|
||||
final float multiplier;
|
||||
@LetterboxReachabilityPosition final int position;
|
||||
try {
|
||||
String arg = getNextArgRequired();
|
||||
multiplier = Float.parseFloat(arg);
|
||||
} catch (NumberFormatException e) {
|
||||
getErrPrintWriter().println("Error: bad multiplier format " + e);
|
||||
return -1;
|
||||
switch (arg) {
|
||||
case "left":
|
||||
position = LETTERBOX_REACHABILITY_POSITION_LEFT;
|
||||
break;
|
||||
case "center":
|
||||
position = LETTERBOX_REACHABILITY_POSITION_CENTER;
|
||||
break;
|
||||
case "right":
|
||||
position = LETTERBOX_REACHABILITY_POSITION_RIGHT;
|
||||
break;
|
||||
default:
|
||||
getErrPrintWriter().println(
|
||||
"Error: 'left', 'center' or 'right' are expected as an argument");
|
||||
return -1;
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
getErrPrintWriter().println(
|
||||
"Error: multiplier should be provided as an argument " + e);
|
||||
"Error: 'left', 'center' or 'right' are expected as an argument" + e);
|
||||
return -1;
|
||||
}
|
||||
synchronized (mInternal.mGlobalLock) {
|
||||
mLetterboxConfiguration.setDefaultPositionMultiplierForReachability(multiplier);
|
||||
mLetterboxConfiguration.setDefaultPositionForReachability(position);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -841,8 +856,8 @@ public class WindowManagerShellCommand extends ShellCommand {
|
||||
case "--isReachabilityEnabled":
|
||||
runSetLetterboxIsReachabilityEnabled(pw);
|
||||
break;
|
||||
case "--defaultPositionMultiplierReachability":
|
||||
runSetLetterboxDefaultPositionMultiplierForReachability(pw);
|
||||
case "--defaultPositionForReachability":
|
||||
runSetLetterboxDefaultPositionForReachability(pw);
|
||||
break;
|
||||
default:
|
||||
getErrPrintWriter().println(
|
||||
@@ -885,8 +900,8 @@ public class WindowManagerShellCommand extends ShellCommand {
|
||||
case "isReachabilityEnabled":
|
||||
mLetterboxConfiguration.getIsReachabilityEnabled();
|
||||
break;
|
||||
case "defaultPositionMultiplierForReachability":
|
||||
mLetterboxConfiguration.getDefaultPositionMultiplierForReachability();
|
||||
case "defaultPositionForReachability":
|
||||
mLetterboxConfiguration.getDefaultPositionForReachability();
|
||||
break;
|
||||
default:
|
||||
getErrPrintWriter().println(
|
||||
@@ -982,7 +997,7 @@ public class WindowManagerShellCommand extends ShellCommand {
|
||||
mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
|
||||
mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
|
||||
mLetterboxConfiguration.resetIsReachabilityEnabled();
|
||||
mLetterboxConfiguration.resetDefaultPositionMultiplierForReachability();
|
||||
mLetterboxConfiguration.resetDefaultPositionForReachability();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,8 +1011,9 @@ public class WindowManagerShellCommand extends ShellCommand {
|
||||
+ mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
|
||||
pw.println("Is reachability enabled: "
|
||||
+ mLetterboxConfiguration.getIsReachabilityEnabled());
|
||||
pw.println("Default position multiplier for reachability: "
|
||||
+ mLetterboxConfiguration.getDefaultPositionMultiplierForReachability());
|
||||
pw.println("Default position for reachability: "
|
||||
+ LetterboxConfiguration.letterboxReachabilityPositionToString(
|
||||
mLetterboxConfiguration.getDefaultPositionForReachability()));
|
||||
|
||||
pw.println("Background type: "
|
||||
+ LetterboxConfiguration.letterboxBackgroundTypeToString(
|
||||
@@ -1135,11 +1151,9 @@ public class WindowManagerShellCommand extends ShellCommand {
|
||||
pw.println(" --isReachabilityEnabled [true|1|false|0]");
|
||||
pw.println(" Whether reachability repositioning is allowed for letterboxed");
|
||||
pw.println(" fullscreen apps in landscape device orientation.");
|
||||
pw.println(" --defaultPositionMultiplierReachability multiplier");
|
||||
pw.println(" Default horizontal position of app window center when reachability is");
|
||||
pw.println(" enabled. If multiplier < 0.0 or > 1, both it and ");
|
||||
pw.println(" R.dimen.config_letterboxDefaultPositionMultiplierForReachability");
|
||||
pw.println(" are ignored and right position (1.0) is used.");
|
||||
pw.println(" --defaultPositionForReachability [left|center|right]");
|
||||
pw.println(" Default horizontal position of app window when reachability is.");
|
||||
pw.println(" enabled.");
|
||||
pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType");
|
||||
pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
|
||||
pw.println(" |horizontalPositionMultiplier|isReachabilityEnabled");
|
||||
|
||||
@@ -63,7 +63,7 @@ public class LetterboxTest {
|
||||
mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
|
||||
() -> mAreCornersRounded, () -> Color.valueOf(mColor),
|
||||
() -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha,
|
||||
/* doubleTapCallback= */ () -> {});
|
||||
/* doubleTapCallback= */ x -> {});
|
||||
mTransaction = spy(StubTransaction.class);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user