Merge "Handle PiP shadow radius in WMShell" into tm-dev
This commit is contained in:
@@ -222,9 +222,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
|
||||
})
|
||||
public @interface WindowConfig {}
|
||||
|
||||
/** @hide */
|
||||
public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5;
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public WindowConfiguration() {
|
||||
unset();
|
||||
|
||||
@@ -47,6 +47,8 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
|
||||
public final float mCornerRadius;
|
||||
|
||||
public final float mShadowRadius;
|
||||
|
||||
private final Rect mWindowCrop;
|
||||
|
||||
private PictureInPictureSurfaceTransaction(Parcel in) {
|
||||
@@ -56,11 +58,12 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
in.readFloatArray(mFloat9);
|
||||
mRotation = in.readFloat();
|
||||
mCornerRadius = in.readFloat();
|
||||
mShadowRadius = in.readFloat();
|
||||
mWindowCrop = in.readTypedObject(Rect.CREATOR);
|
||||
}
|
||||
|
||||
private PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position,
|
||||
@Nullable float[] float9, float rotation, float cornerRadius,
|
||||
@Nullable float[] float9, float rotation, float cornerRadius, float shadowRadius,
|
||||
@Nullable Rect windowCrop) {
|
||||
mAlpha = alpha;
|
||||
mPosition = position;
|
||||
@@ -73,12 +76,14 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
mRotation = rotation;
|
||||
}
|
||||
mCornerRadius = cornerRadius;
|
||||
mShadowRadius = shadowRadius;
|
||||
mWindowCrop = (windowCrop == null) ? null : new Rect(windowCrop);
|
||||
}
|
||||
|
||||
public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) {
|
||||
this(other.mAlpha, other.mPosition,
|
||||
other.mFloat9, other.mRotation, other.mCornerRadius, other.mWindowCrop);
|
||||
other.mFloat9, other.mRotation, other.mCornerRadius, other.mShadowRadius,
|
||||
other.mWindowCrop);
|
||||
}
|
||||
|
||||
/** @return {@link Matrix} from {@link #mFloat9} */
|
||||
@@ -93,6 +98,11 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
return mCornerRadius > 0;
|
||||
}
|
||||
|
||||
/** @return {@code true} if this transaction contains setting shadow radius. */
|
||||
public boolean hasShadowRadiusSet() {
|
||||
return mShadowRadius > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -103,13 +113,14 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
&& Arrays.equals(mFloat9, that.mFloat9)
|
||||
&& Objects.equals(mRotation, that.mRotation)
|
||||
&& Objects.equals(mCornerRadius, that.mCornerRadius)
|
||||
&& Objects.equals(mShadowRadius, that.mShadowRadius)
|
||||
&& Objects.equals(mWindowCrop, that.mWindowCrop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mAlpha, mPosition, Arrays.hashCode(mFloat9),
|
||||
mRotation, mCornerRadius, mWindowCrop);
|
||||
mRotation, mCornerRadius, mShadowRadius, mWindowCrop);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,6 +135,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
out.writeFloatArray(mFloat9);
|
||||
out.writeFloat(mRotation);
|
||||
out.writeFloat(mCornerRadius);
|
||||
out.writeFloat(mShadowRadius);
|
||||
out.writeTypedObject(mWindowCrop, 0 /* flags */);
|
||||
}
|
||||
|
||||
@@ -136,6 +148,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
+ " matrix=" + matrix.toShortString()
|
||||
+ " rotation=" + mRotation
|
||||
+ " cornerRadius=" + mCornerRadius
|
||||
+ " shadowRadius=" + mShadowRadius
|
||||
+ " crop=" + mWindowCrop
|
||||
+ ")";
|
||||
}
|
||||
@@ -156,6 +169,9 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
if (surfaceTransaction.hasCornerRadiusSet()) {
|
||||
tx.setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius);
|
||||
}
|
||||
if (surfaceTransaction.hasShadowRadiusSet()) {
|
||||
tx.setShadowRadius(surfaceControl, surfaceTransaction.mShadowRadius);
|
||||
}
|
||||
if (surfaceTransaction.mAlpha != NOT_SET) {
|
||||
tx.setAlpha(surfaceControl, surfaceTransaction.mAlpha);
|
||||
}
|
||||
@@ -178,6 +194,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
private float[] mFloat9;
|
||||
private float mRotation;
|
||||
private float mCornerRadius = NOT_SET;
|
||||
private float mShadowRadius = NOT_SET;
|
||||
private Rect mWindowCrop;
|
||||
|
||||
public Builder setAlpha(float alpha) {
|
||||
@@ -201,6 +218,11 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setShadowRadius(float shadowRadius) {
|
||||
mShadowRadius = shadowRadius;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setWindowCrop(@NonNull Rect windowCrop) {
|
||||
mWindowCrop = new Rect(windowCrop);
|
||||
return this;
|
||||
@@ -208,7 +230,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable {
|
||||
|
||||
public PictureInPictureSurfaceTransaction build() {
|
||||
return new PictureInPictureSurfaceTransaction(mAlpha, mPosition,
|
||||
mFloat9, mRotation, mCornerRadius, mWindowCrop);
|
||||
mFloat9, mRotation, mCornerRadius, mShadowRadius, mWindowCrop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
package com.android.internal.policy;
|
||||
|
||||
import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||
import static android.os.Build.VERSION_CODES.M;
|
||||
import static android.os.Build.VERSION_CODES.N;
|
||||
@@ -2549,9 +2547,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
|
||||
// Convert the DP elevation into physical pixels.
|
||||
elevation = dipToPx(elevation);
|
||||
mElevationAdjustedForStack = true;
|
||||
} else if (windowingMode == WINDOWING_MODE_PINNED) {
|
||||
elevation = dipToPx(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP);
|
||||
mElevationAdjustedForStack = true;
|
||||
} else {
|
||||
mElevationAdjustedForStack = false;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,10 @@
|
||||
<!-- PIP stash offset size, which is the width of visible PIP region when stashed. -->
|
||||
<dimen name="pip_stash_offset">32dp</dimen>
|
||||
|
||||
<!-- PIP shadow radius, originally as
|
||||
WindowConfiguration#PINNED_WINDOWING_MODE_ELEVATION_IN_DIP -->
|
||||
<dimen name="pip_shadow_radius">5dp</dimen>
|
||||
|
||||
<dimen name="dismiss_target_x_size">24dp</dimen>
|
||||
<dimen name="floating_dismiss_bottom_margin">50dp</dimen>
|
||||
|
||||
|
||||
@@ -26,12 +26,13 @@ oneway interface IPipAnimationListener {
|
||||
void onPipAnimationStarted();
|
||||
|
||||
/**
|
||||
* Notifies the listener about PiP round corner radius changes.
|
||||
* Notifies the listener about PiP resource dimensions changed.
|
||||
* Listener can expect an immediate callback the first time they attach.
|
||||
*
|
||||
* @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
|
||||
* @param shadowRadius the pixel value of the shadow radius, zero means it's disabled.
|
||||
*/
|
||||
void onPipCornerRadiusChanged(int cornerRadius);
|
||||
void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius);
|
||||
|
||||
/**
|
||||
* Notifies the listener that user leaves PiP by tapping on the expand button.
|
||||
|
||||
@@ -489,7 +489,8 @@ public class PipAnimationController {
|
||||
final float alpha = getStartValue() * (1 - fraction) + getEndValue() * fraction;
|
||||
setCurrentValue(alpha);
|
||||
getSurfaceTransactionHelper().alpha(tx, leash, alpha)
|
||||
.round(tx, leash, shouldApplyCornerRadius());
|
||||
.round(tx, leash, shouldApplyCornerRadius())
|
||||
.shadow(tx, leash);
|
||||
tx.apply();
|
||||
}
|
||||
|
||||
@@ -502,7 +503,8 @@ public class PipAnimationController {
|
||||
getSurfaceTransactionHelper()
|
||||
.resetScale(tx, leash, getDestinationBounds())
|
||||
.crop(tx, leash, getDestinationBounds())
|
||||
.round(tx, leash, shouldApplyCornerRadius());
|
||||
.round(tx, leash, shouldApplyCornerRadius())
|
||||
.shadow(tx, leash);
|
||||
tx.show(leash);
|
||||
tx.apply();
|
||||
}
|
||||
@@ -589,7 +591,8 @@ public class PipAnimationController {
|
||||
} else {
|
||||
getSurfaceTransactionHelper().crop(tx, leash, base)
|
||||
.scale(tx, leash, base, bounds, angle)
|
||||
.round(tx, leash, base, bounds);
|
||||
.round(tx, leash, base, bounds)
|
||||
.shadow(tx, leash);
|
||||
}
|
||||
} else {
|
||||
final Rect insets = computeInsets(fraction);
|
||||
@@ -598,8 +601,9 @@ public class PipAnimationController {
|
||||
if (shouldApplyCornerRadius()) {
|
||||
final Rect sourceBounds = new Rect(initialContainerRect);
|
||||
sourceBounds.inset(insets);
|
||||
getSurfaceTransactionHelper().round(tx, leash,
|
||||
sourceBounds, bounds);
|
||||
getSurfaceTransactionHelper()
|
||||
.round(tx, leash, sourceBounds, bounds)
|
||||
.shadow(tx, leash);
|
||||
}
|
||||
}
|
||||
if (!handlePipTransaction(leash, tx, bounds)) {
|
||||
@@ -650,7 +654,9 @@ public class PipAnimationController {
|
||||
insets, degree, x, y, isOutPipDirection,
|
||||
rotationDelta == ROTATION_270 /* clockwise */);
|
||||
if (shouldApplyCornerRadius()) {
|
||||
getSurfaceTransactionHelper().round(tx, leash, sourceBounds, bounds);
|
||||
getSurfaceTransactionHelper()
|
||||
.round(tx, leash, sourceBounds, bounds)
|
||||
.shadow(tx, leash);
|
||||
}
|
||||
tx.apply();
|
||||
}
|
||||
@@ -668,7 +674,8 @@ public class PipAnimationController {
|
||||
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
|
||||
getSurfaceTransactionHelper()
|
||||
.alpha(tx, leash, 1f)
|
||||
.round(tx, leash, shouldApplyCornerRadius());
|
||||
.round(tx, leash, shouldApplyCornerRadius())
|
||||
.shadow(tx, leash);
|
||||
// TODO(b/178632364): this is a work around for the black background when
|
||||
// entering PiP in buttion navigation mode.
|
||||
if (isInPipDirection(direction)) {
|
||||
|
||||
@@ -37,6 +37,7 @@ public class PipSurfaceTransactionHelper {
|
||||
private final Rect mTmpDestinationRect = new Rect();
|
||||
|
||||
private int mCornerRadius;
|
||||
private int mShadowRadius;
|
||||
|
||||
/**
|
||||
* Called when display size or font size of settings changed
|
||||
@@ -45,6 +46,7 @@ public class PipSurfaceTransactionHelper {
|
||||
*/
|
||||
public void onDensityOrFontScaleChanged(Context context) {
|
||||
mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
|
||||
mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,14 +202,11 @@ public class PipSurfaceTransactionHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-parents the snapshot to the parent's surface control and shows it.
|
||||
* Operates the shadow radius on a given transaction and leash
|
||||
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
|
||||
*/
|
||||
public PipSurfaceTransactionHelper reparentAndShowSurfaceSnapshot(
|
||||
SurfaceControl.Transaction t, SurfaceControl parent, SurfaceControl snapshot) {
|
||||
t.reparent(snapshot, parent);
|
||||
t.setLayer(snapshot, Integer.MAX_VALUE);
|
||||
t.show(snapshot);
|
||||
t.apply();
|
||||
public PipSurfaceTransactionHelper shadow(SurfaceControl.Transaction tx, SurfaceControl leash) {
|
||||
tx.setShadowRadius(leash, mShadowRadius);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,12 +131,13 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
void onPipAnimationStarted();
|
||||
|
||||
/**
|
||||
* Notifies the listener about PiP round corner radius changes.
|
||||
* Notifies the listener about PiP resource dimensions changed.
|
||||
* Listener can expect an immediate callback the first time they attach.
|
||||
*
|
||||
* @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
|
||||
* @param shadowRadius the pixel value of the shadow radius, zero means it's disabled.
|
||||
*/
|
||||
void onPipCornerRadiusChanged(int cornerRadius);
|
||||
void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius);
|
||||
|
||||
/**
|
||||
* Notifies the listener that user leaves PiP by tapping on the expand button.
|
||||
@@ -479,7 +480,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
|
||||
private void onDensityOrFontScaleChanged() {
|
||||
mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
|
||||
onPipCornerRadiusChanged();
|
||||
onPipResourceDimensionsChanged();
|
||||
}
|
||||
|
||||
private void onOverlayChanged() {
|
||||
@@ -590,14 +591,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
|
||||
private void setPinnedStackAnimationListener(PipAnimationListener callback) {
|
||||
mPinnedStackAnimationRecentsCallback = callback;
|
||||
onPipCornerRadiusChanged();
|
||||
onPipResourceDimensionsChanged();
|
||||
}
|
||||
|
||||
private void onPipCornerRadiusChanged() {
|
||||
private void onPipResourceDimensionsChanged() {
|
||||
if (mPinnedStackAnimationRecentsCallback != null) {
|
||||
final int cornerRadius =
|
||||
mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
|
||||
mPinnedStackAnimationRecentsCallback.onPipCornerRadiusChanged(cornerRadius);
|
||||
mPinnedStackAnimationRecentsCallback.onPipResourceDimensionsChanged(
|
||||
mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius),
|
||||
mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -916,8 +917,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipCornerRadiusChanged(int cornerRadius) {
|
||||
mListener.call(l -> l.onPipCornerRadiusChanged(cornerRadius));
|
||||
public void onPipResourceDimensionsChanged(int cornerRadius, int shadowRadius) {
|
||||
mListener.call(l -> l.onPipResourceDimensionsChanged(cornerRadius, shadowRadius));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,14 +30,16 @@ import android.window.PictureInPictureSurfaceTransaction;
|
||||
*/
|
||||
public class PipSurfaceTransactionHelper {
|
||||
private final int mCornerRadius;
|
||||
private final int mShadowRadius;
|
||||
private final Matrix mTmpTransform = new Matrix();
|
||||
private final float[] mTmpFloat9 = new float[9];
|
||||
private final RectF mTmpSourceRectF = new RectF();
|
||||
private final RectF mTmpDestinationRectF = new RectF();
|
||||
private final Rect mTmpDestinationRect = new Rect();
|
||||
|
||||
public PipSurfaceTransactionHelper(int cornerRadius) {
|
||||
public PipSurfaceTransactionHelper(int cornerRadius, int shadowRadius) {
|
||||
mCornerRadius = cornerRadius;
|
||||
mShadowRadius = shadowRadius;
|
||||
}
|
||||
|
||||
public PictureInPictureSurfaceTransaction scale(
|
||||
@@ -52,9 +54,10 @@ public class PipSurfaceTransactionHelper {
|
||||
final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds);
|
||||
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
|
||||
.setPosition(leash, positionX, positionY)
|
||||
.setCornerRadius(leash, cornerRadius);
|
||||
.setCornerRadius(leash, cornerRadius)
|
||||
.setShadowRadius(leash, mShadowRadius);
|
||||
return newPipSurfaceTransaction(positionX, positionY,
|
||||
mTmpFloat9, 0 /* rotation */, cornerRadius, sourceBounds);
|
||||
mTmpFloat9, 0 /* rotation */, cornerRadius, mShadowRadius, sourceBounds);
|
||||
}
|
||||
|
||||
public PictureInPictureSurfaceTransaction scale(
|
||||
@@ -69,9 +72,10 @@ public class PipSurfaceTransactionHelper {
|
||||
final float cornerRadius = getScaledCornerRadius(sourceBounds, destinationBounds);
|
||||
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
|
||||
.setPosition(leash, positionX, positionY)
|
||||
.setCornerRadius(leash, cornerRadius);
|
||||
.setCornerRadius(leash, cornerRadius)
|
||||
.setShadowRadius(leash, mShadowRadius);
|
||||
return newPipSurfaceTransaction(positionX, positionY,
|
||||
mTmpFloat9, degree, cornerRadius, sourceBounds);
|
||||
mTmpFloat9, degree, cornerRadius, mShadowRadius, sourceBounds);
|
||||
}
|
||||
|
||||
public PictureInPictureSurfaceTransaction scaleAndCrop(
|
||||
@@ -92,9 +96,10 @@ public class PipSurfaceTransactionHelper {
|
||||
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
|
||||
.setWindowCrop(leash, mTmpDestinationRect)
|
||||
.setPosition(leash, left, top)
|
||||
.setCornerRadius(leash, cornerRadius);
|
||||
.setCornerRadius(leash, cornerRadius)
|
||||
.setShadowRadius(leash, mShadowRadius);
|
||||
return newPipSurfaceTransaction(left, top,
|
||||
mTmpFloat9, 0 /* rotation */, cornerRadius, mTmpDestinationRect);
|
||||
mTmpFloat9, 0 /* rotation */, cornerRadius, mShadowRadius, mTmpDestinationRect);
|
||||
}
|
||||
|
||||
public PictureInPictureSurfaceTransaction scaleAndRotate(
|
||||
@@ -124,9 +129,10 @@ public class PipSurfaceTransactionHelper {
|
||||
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
|
||||
.setWindowCrop(leash, mTmpDestinationRect)
|
||||
.setPosition(leash, adjustedPositionX, adjustedPositionY)
|
||||
.setCornerRadius(leash, cornerRadius);
|
||||
.setCornerRadius(leash, cornerRadius)
|
||||
.setShadowRadius(leash, mShadowRadius);
|
||||
return newPipSurfaceTransaction(adjustedPositionX, adjustedPositionY,
|
||||
mTmpFloat9, degree, cornerRadius, mTmpDestinationRect);
|
||||
mTmpFloat9, degree, cornerRadius, mShadowRadius, mTmpDestinationRect);
|
||||
}
|
||||
|
||||
/** @return the round corner radius scaled by given from and to bounds */
|
||||
@@ -137,12 +143,13 @@ public class PipSurfaceTransactionHelper {
|
||||
}
|
||||
|
||||
private static PictureInPictureSurfaceTransaction newPipSurfaceTransaction(
|
||||
float posX, float posY, float[] float9, float rotation, float cornerRadius,
|
||||
Rect windowCrop) {
|
||||
float posX, float posY, float[] float9, float rotation,
|
||||
float cornerRadius, float shadowRadius, Rect windowCrop) {
|
||||
return new PictureInPictureSurfaceTransaction.Builder()
|
||||
.setPosition(posX, posY)
|
||||
.setTransform(float9, rotation)
|
||||
.setCornerRadius(cornerRadius)
|
||||
.setShadowRadius(shadowRadius)
|
||||
.setWindowCrop(windowCrop)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||
import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
@@ -4341,9 +4340,7 @@ class Task extends TaskFragment {
|
||||
int elevation = 0;
|
||||
|
||||
// Get elevation for a specific windowing mode.
|
||||
if (inPinnedWindowingMode()) {
|
||||
elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
|
||||
} else if (inFreeformWindowingMode()) {
|
||||
if (inFreeformWindowingMode()) {
|
||||
elevation = taskIsFocused
|
||||
? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user