Merge "Add shadow for minimized dock" into nyc-dev
am: a5df489
* commit 'a5df489c9c56b1ac5b0f1acef07454ea438b5367':
Add shadow for minimized dock
Change-Id: Iab5e97a8a5cb521aadf519359816ff2c48de7e71
This commit is contained in:
@@ -42,4 +42,9 @@ oneway interface IDockedStackListener {
|
|||||||
* @param animDuration The duration of the animation for changing the minimized state.
|
* @param animDuration The duration of the animation for changing the minimized state.
|
||||||
*/
|
*/
|
||||||
void onDockedStackMinimizedChanged(boolean minimized, long animDuration);
|
void onDockedStackMinimizedChanged(boolean minimized, long animDuration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when window manager repositioned the docked stack after a screen rotation change.
|
||||||
|
*/
|
||||||
|
void onDockSideChanged(int newDockSide);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,11 @@
|
|||||||
android:id="@+id/docked_divider_background"
|
android:id="@+id/docked_divider_background"
|
||||||
android:background="@color/docked_divider_background"/>
|
android:background="@color/docked_divider_background"/>
|
||||||
|
|
||||||
|
<com.android.systemui.stackdivider.MinimizedDockShadow
|
||||||
|
style="@style/DockedDividerMinimizedShadow"
|
||||||
|
android:id="@+id/minimized_dock_shadow"
|
||||||
|
android:alpha="0"/>">
|
||||||
|
|
||||||
<com.android.systemui.stackdivider.DividerHandleView
|
<com.android.systemui.stackdivider.DividerHandleView
|
||||||
style="@style/DockedDividerHandle"
|
style="@style/DockedDividerHandle"
|
||||||
android:id="@+id/docked_divider_handle"
|
android:id="@+id/docked_divider_handle"
|
||||||
|
|||||||
@@ -31,4 +31,8 @@
|
|||||||
<item name="android:layout_height">96dp</item>
|
<item name="android:layout_height">96dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="DockedDividerMinimizedShadow">
|
||||||
|
<item name="android:layout_width">8dp</item>
|
||||||
|
<item name="android:layout_height">match_parent</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -151,7 +151,9 @@
|
|||||||
|
|
||||||
<color name="docked_divider_background">#ff000000</color>
|
<color name="docked_divider_background">#ff000000</color>
|
||||||
<color name="docked_divider_handle">#ffffff</color>
|
<color name="docked_divider_handle">#ffffff</color>
|
||||||
<drawable name="forced_resizable_background">#40000000</drawable>
|
<drawable name="forced_resizable_background">#59000000</drawable>
|
||||||
|
<color name="minimize_dock_shadow_start">#60000000</color>
|
||||||
|
<color name="minimize_dock_shadow_end">#00000000</color>
|
||||||
|
|
||||||
<color name="default_remote_input_background">@*android:color/notification_default_color</color>
|
<color name="default_remote_input_background">@*android:color/notification_default_color</color>
|
||||||
<color name="remote_input_hint">#99ffffff</color>
|
<color name="remote_input_hint">#99ffffff</color>
|
||||||
|
|||||||
@@ -308,6 +308,11 @@
|
|||||||
<item name="android:layout_gravity">center_vertical</item>
|
<item name="android:layout_gravity">center_vertical</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="DockedDividerMinimizedShadow">
|
||||||
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
<item name="android:layout_height">8dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="DockedDividerHandle">
|
<style name="DockedDividerHandle">
|
||||||
<item name="android:layout_gravity">center_horizontal</item>
|
<item name="android:layout_gravity">center_horizontal</item>
|
||||||
<item name="android:layout_width">96dp</item>
|
<item name="android:layout_width">96dp</item>
|
||||||
|
|||||||
@@ -146,5 +146,10 @@ public class Divider extends SystemUI {
|
|||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
updateMinimizedDockedStack(minimized, animDuration);
|
updateMinimizedDockedStack(minimized, animDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDockSideChanged(final int newDockSide) throws RemoteException {
|
||||||
|
mView.post(() -> mView.notifyDockSideChanged(newDockSide));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
/**
|
/**
|
||||||
* How much the background gets scaled when we are in the minimized dock state.
|
* How much the background gets scaled when we are in the minimized dock state.
|
||||||
*/
|
*/
|
||||||
private static final float MINIMIZE_DOCK_SCALE = 0.375f;
|
private static final float MINIMIZE_DOCK_SCALE = 0f;
|
||||||
|
|
||||||
private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
|
private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
|
||||||
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
|
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
|
||||||
@@ -97,6 +97,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
|
|
||||||
private DividerHandleView mHandle;
|
private DividerHandleView mHandle;
|
||||||
private View mBackground;
|
private View mBackground;
|
||||||
|
private MinimizedDockShadow mMinimizedShadow;
|
||||||
private int mStartX;
|
private int mStartX;
|
||||||
private int mStartY;
|
private int mStartY;
|
||||||
private int mStartPosition;
|
private int mStartPosition;
|
||||||
@@ -203,6 +204,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
|
mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
|
||||||
mBackground = findViewById(R.id.docked_divider_background);
|
mBackground = findViewById(R.id.docked_divider_background);
|
||||||
|
mMinimizedShadow = (MinimizedDockShadow) findViewById(R.id.minimized_dock_shadow);
|
||||||
mHandle.setOnTouchListener(this);
|
mHandle.setOnTouchListener(this);
|
||||||
mDividerWindowWidth = getResources().getDimensionPixelSize(
|
mDividerWindowWidth = getResources().getDimensionPixelSize(
|
||||||
com.android.internal.R.dimen.docked_stack_divider_thickness);
|
com.android.internal.R.dimen.docked_stack_divider_thickness);
|
||||||
@@ -269,6 +271,18 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
super.onLayout(changed, left, top, right, bottom);
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
|
int minimizeLeft = 0;
|
||||||
|
int minimizeTop = 0;
|
||||||
|
if (mDockSide == WindowManager.DOCKED_TOP) {
|
||||||
|
minimizeTop = mBackground.getTop();
|
||||||
|
} else if (mDockSide == WindowManager.DOCKED_LEFT) {
|
||||||
|
minimizeLeft = mBackground.getLeft();
|
||||||
|
} else if (mDockSide == WindowManager.DOCKED_RIGHT) {
|
||||||
|
minimizeLeft = mBackground.getRight() - mMinimizedShadow.getWidth();
|
||||||
|
}
|
||||||
|
mMinimizedShadow.layout(minimizeLeft, minimizeTop,
|
||||||
|
minimizeLeft + mMinimizedShadow.getMeasuredWidth(),
|
||||||
|
minimizeTop + mMinimizedShadow.getMeasuredHeight());
|
||||||
if (changed) {
|
if (changed) {
|
||||||
mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
|
mWindowManagerProxy.setTouchRegion(new Rect(mHandle.getLeft(), mHandle.getTop(),
|
||||||
mHandle.getRight(), mHandle.getBottom()));
|
mHandle.getRight(), mHandle.getBottom()));
|
||||||
@@ -327,6 +341,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
|
|
||||||
private void updateDockSide() {
|
private void updateDockSide() {
|
||||||
mDockSide = mWindowManagerProxy.getDockSide();
|
mDockSide = mWindowManagerProxy.getDockSide();
|
||||||
|
mMinimizedShadow.setDockSide(mDockSide);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSnapAlgorithm() {
|
private void initializeSnapAlgorithm() {
|
||||||
@@ -541,6 +556,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
: mBackground.getWidth());
|
: mBackground.getWidth());
|
||||||
mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
|
mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
|
||||||
}
|
}
|
||||||
|
mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
|
||||||
mDockedStackMinimized = minimized;
|
mDockedStackMinimized = minimized;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,6 +582,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
if (!minimized) {
|
if (!minimized) {
|
||||||
mBackground.animate().withEndAction(mResetBackgroundRunnable);
|
mBackground.animate().withEndAction(mResetBackgroundRunnable);
|
||||||
}
|
}
|
||||||
|
mMinimizedShadow.animate()
|
||||||
|
.alpha(minimized ? 1f : 0f)
|
||||||
|
.setInterpolator(Interpolators.ALPHA_IN)
|
||||||
|
.setDuration(animDuration)
|
||||||
|
.start();
|
||||||
mBackground.animate()
|
mBackground.animate()
|
||||||
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
|
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
|
||||||
.setDuration(animDuration)
|
.setDuration(animDuration)
|
||||||
@@ -578,6 +599,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
mBackground.setPivotY(mBackground.getHeight() / 2);
|
mBackground.setPivotY(mBackground.getHeight() / 2);
|
||||||
mBackground.setScaleX(1f);
|
mBackground.setScaleX(1f);
|
||||||
mBackground.setScaleY(1f);
|
mBackground.setScaleY(1f);
|
||||||
|
mMinimizedShadow.setAlpha(0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -586,6 +608,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
|||||||
updateDisplayInfo();
|
updateDisplayInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void notifyDockSideChanged(int newDockSide) {
|
||||||
|
mDockSide = newDockSide;
|
||||||
|
mMinimizedShadow.setDockSide(mDockSide);
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
private void updateDisplayInfo() {
|
private void updateDisplayInfo() {
|
||||||
final DisplayManager displayManager =
|
final DisplayManager displayManager =
|
||||||
(DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
|
(DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.stackdivider;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.LinearGradient;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Shader;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import com.android.systemui.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shadow for the minimized dock state on homescreen.
|
||||||
|
*/
|
||||||
|
public class MinimizedDockShadow extends View {
|
||||||
|
|
||||||
|
private final Paint mShadowPaint = new Paint();
|
||||||
|
|
||||||
|
private int mDockSide = WindowManager.DOCKED_INVALID;
|
||||||
|
|
||||||
|
public MinimizedDockShadow(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDockSide(int dockSide) {
|
||||||
|
if (dockSide != mDockSide) {
|
||||||
|
mDockSide = dockSide;
|
||||||
|
updatePaint(getLeft(), getTop(), getRight(), getBottom());
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePaint(int left, int top, int right, int bottom) {
|
||||||
|
int startColor = mContext.getResources().getColor(
|
||||||
|
R.color.minimize_dock_shadow_start, null);
|
||||||
|
int endColor = mContext.getResources().getColor(
|
||||||
|
R.color.minimize_dock_shadow_end, null);
|
||||||
|
final int middleColor = Color.argb(
|
||||||
|
(Color.alpha(startColor) + Color.alpha(endColor)) / 2, 0, 0, 0);
|
||||||
|
final int quarter = Color.argb(
|
||||||
|
(int) (Color.alpha(startColor) * 0.25f + Color.alpha(endColor) * 0.75f),
|
||||||
|
0, 0, 0);
|
||||||
|
if (mDockSide == WindowManager.DOCKED_TOP) {
|
||||||
|
mShadowPaint.setShader(new LinearGradient(
|
||||||
|
0, 0, 0, bottom - top,
|
||||||
|
new int[] { startColor, middleColor, quarter, endColor },
|
||||||
|
new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
|
||||||
|
} else if (mDockSide == WindowManager.DOCKED_LEFT) {
|
||||||
|
mShadowPaint.setShader(new LinearGradient(
|
||||||
|
0, 0, right - left, 0,
|
||||||
|
new int[] { startColor, middleColor, quarter, endColor },
|
||||||
|
new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
|
||||||
|
} else if (mDockSide == WindowManager.DOCKED_RIGHT) {
|
||||||
|
mShadowPaint.setShader(new LinearGradient(
|
||||||
|
right - left, 0, 0, 0,
|
||||||
|
new int[] { startColor, middleColor, quarter, endColor },
|
||||||
|
new float[] { 0f, 0.35f, 0.6f, 1f }, Shader.TileMode.CLAMP));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
|
if (changed) {
|
||||||
|
updatePaint(left, top, right, bottom);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
canvas.drawRect(0, 0, getWidth(), getHeight(), mShadowPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasOverlappingRendering() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -526,6 +526,10 @@ public class NavigationBarView extends LinearLayout {
|
|||||||
public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
|
public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDockSideChanged(int newDockSide) throws RemoteException {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Failed registering docked stack exists listener", e);
|
Log.e(TAG, "Failed registering docked stack exists listener", e);
|
||||||
|
|||||||
@@ -270,6 +270,19 @@ public class DockedStackDividerController implements DimLayerUser {
|
|||||||
mDockedStackListeners.finishBroadcast();
|
mDockedStackListeners.finishBroadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void notifyDockSideChanged(int newDockSide) {
|
||||||
|
final int size = mDockedStackListeners.beginBroadcast();
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
|
||||||
|
try {
|
||||||
|
listener.onDockSideChanged(newDockSide);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG_WM, "Error delivering dock side changed event.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDockedStackListeners.finishBroadcast();
|
||||||
|
}
|
||||||
|
|
||||||
void registerDockedStackListener(IDockedStackListener listener) {
|
void registerDockedStackListener(IDockedStackListener listener) {
|
||||||
mDockedStackListeners.register(listener);
|
mDockedStackListeners.register(listener);
|
||||||
notifyDockedDividerVisibilityChanged(wasVisible());
|
notifyDockedDividerVisibilityChanged(wasVisible());
|
||||||
|
|||||||
@@ -16,6 +16,20 @@
|
|||||||
|
|
||||||
package com.android.server.wm;
|
package com.android.server.wm;
|
||||||
|
|
||||||
|
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
|
||||||
|
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
|
||||||
|
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
|
||||||
|
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
|
||||||
|
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
||||||
|
import static android.view.WindowManager.DOCKED_BOTTOM;
|
||||||
|
import static android.view.WindowManager.DOCKED_INVALID;
|
||||||
|
import static android.view.WindowManager.DOCKED_LEFT;
|
||||||
|
import static android.view.WindowManager.DOCKED_RIGHT;
|
||||||
|
import static android.view.WindowManager.DOCKED_TOP;
|
||||||
|
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
|
||||||
|
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||||
|
import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
|
||||||
|
|
||||||
import android.app.ActivityManager.StackId;
|
import android.app.ActivityManager.StackId;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
@@ -35,20 +49,6 @@ import com.android.server.EventLogTags;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
|
|
||||||
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
|
|
||||||
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
|
|
||||||
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
|
|
||||||
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
|
|
||||||
import static android.view.WindowManager.DOCKED_BOTTOM;
|
|
||||||
import static android.view.WindowManager.DOCKED_INVALID;
|
|
||||||
import static android.view.WindowManager.DOCKED_LEFT;
|
|
||||||
import static android.view.WindowManager.DOCKED_RIGHT;
|
|
||||||
import static android.view.WindowManager.DOCKED_TOP;
|
|
||||||
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
|
|
||||||
import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
|
|
||||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
|
||||||
|
|
||||||
public class TaskStack implements DimLayer.DimLayerUser,
|
public class TaskStack implements DimLayer.DimLayerUser,
|
||||||
BoundsAnimationController.AnimateBoundsUser {
|
BoundsAnimationController.AnimateBoundsUser {
|
||||||
|
|
||||||
@@ -379,10 +379,15 @@ public class TaskStack implements DimLayer.DimLayerUser,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID;
|
||||||
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
|
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
|
||||||
if (mStackId == DOCKED_STACK_ID) {
|
if (mStackId == DOCKED_STACK_ID) {
|
||||||
repositionDockedStackAfterRotation(mTmpRect2);
|
repositionDockedStackAfterRotation(mTmpRect2);
|
||||||
snapDockedStackAfterRotation(mTmpRect2);
|
snapDockedStackAfterRotation(mTmpRect2);
|
||||||
|
final int newDockSide = getDockSide(mTmpRect2);
|
||||||
|
if (oldDockSide != newDockSide) {
|
||||||
|
mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scheduleResize) {
|
if (scheduleResize) {
|
||||||
|
|||||||
Reference in New Issue
Block a user