Merge "Convert existing flags to new system." into sc-v2-dev
This commit is contained in:
@@ -23,14 +23,75 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* List of {@link Flag} objects for use in SystemUI.
|
* List of {@link Flag} objects for use in SystemUI.
|
||||||
*
|
*
|
||||||
* Flag Ids are integers. They must be unique.
|
* Flag Ids are integers.
|
||||||
|
* Ids must be unique. This is enforced in a unit test.
|
||||||
|
* Ids need not be sequential. Flags can "claim" a chunk of ids for flags in related featurs with
|
||||||
|
* a comment. This is purely for organizational purposes.
|
||||||
*
|
*
|
||||||
* On public release builds, flags will always return their default value. There is no way to
|
* On public release builds, flags will always return their default value. There is no way to
|
||||||
* change their value on release builds.
|
* change their value on release builds.
|
||||||
|
*
|
||||||
|
* See {@link FeatureFlagManager} for instructions on flipping the flags via adb.
|
||||||
*/
|
*/
|
||||||
public class Flags {
|
public class Flags {
|
||||||
public static final BooleanFlag THE_FIRST_FLAG = new BooleanFlag(1, false);
|
public static final BooleanFlag TEAMFOOD = new BooleanFlag(1, false);
|
||||||
|
|
||||||
|
/***************************************/
|
||||||
|
// 100 - notification
|
||||||
|
public static final BooleanFlag NEW_NOTIFICATION_PIPELINE =
|
||||||
|
new BooleanFlag(100, true);
|
||||||
|
|
||||||
|
public static final BooleanFlag NEW_NOTIFICATION_PIPELINE_RENDERING =
|
||||||
|
new BooleanFlag(101, false);
|
||||||
|
|
||||||
|
public static final BooleanFlag NOTIFICATION_UPDATES =
|
||||||
|
new BooleanFlag(102, true);
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************/
|
||||||
|
// 200 - keyguard/lockscreen
|
||||||
|
public static final BooleanFlag KEYGUARD_LAYOUT =
|
||||||
|
new BooleanFlag(200, true);
|
||||||
|
|
||||||
|
public static final BooleanFlag LOCKSCREEN_ANIMATIONS =
|
||||||
|
new BooleanFlag(201, true);
|
||||||
|
|
||||||
|
public static final BooleanFlag NEW_UNLOCK_SWIPE_ANIMATION =
|
||||||
|
new BooleanFlag(202, true);
|
||||||
|
|
||||||
|
/***************************************/
|
||||||
|
// 300 - power menu
|
||||||
|
public static final BooleanFlag POWER_MENU_LITE =
|
||||||
|
new BooleanFlag(300, true);
|
||||||
|
|
||||||
|
/***************************************/
|
||||||
|
// 400 - smartspace
|
||||||
|
public static final BooleanFlag SMARTSPACE_DEDUPING =
|
||||||
|
new BooleanFlag(400, true);
|
||||||
|
|
||||||
|
public static final BooleanFlag SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED =
|
||||||
|
new BooleanFlag(401, false);
|
||||||
|
|
||||||
|
/***************************************/
|
||||||
|
// 500 - quick settings
|
||||||
|
public static final BooleanFlag NEW_USER_SWITCHER =
|
||||||
|
new BooleanFlag(500, true);
|
||||||
|
|
||||||
|
/***************************************/
|
||||||
|
// 600- status bar
|
||||||
|
public static final BooleanFlag COMBINED_STATUS_BAR_SIGNAL_ICONS =
|
||||||
|
new BooleanFlag(501, false);
|
||||||
|
|
||||||
|
/***************************************/
|
||||||
|
// 700 - dialer/calls
|
||||||
|
public static final BooleanFlag ONGOING_CALL_STATUS_BAR_CHIP =
|
||||||
|
new BooleanFlag(600, true);
|
||||||
|
|
||||||
|
public static final BooleanFlag ONGOING_CALL_IN_IMMERSIVE =
|
||||||
|
new BooleanFlag(601, true);
|
||||||
|
|
||||||
|
public static final BooleanFlag ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP =
|
||||||
|
new BooleanFlag(602, true);
|
||||||
|
|
||||||
// Pay no attention to the reflection behind the curtain.
|
// Pay no attention to the reflection behind the curtain.
|
||||||
// ========================== Curtain ==========================
|
// ========================== Curtain ==========================
|
||||||
|
|||||||
@@ -18,40 +18,12 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<bool name="are_flags_overrideable">false</bool>
|
<bool name="are_flags_overrideable">false</bool>
|
||||||
|
|
||||||
<bool name="flag_notification_pipeline2">true</bool>
|
|
||||||
<bool name="flag_notification_pipeline2_rendering">false</bool>
|
|
||||||
<bool name="flag_notif_updates">true</bool>
|
|
||||||
|
|
||||||
<bool name="flag_monet">true</bool>
|
<bool name="flag_monet">true</bool>
|
||||||
|
|
||||||
<!-- People Tile flag -->
|
<!-- People Tile flag -->
|
||||||
<bool name="flag_conversations">false</bool>
|
<bool name="flag_conversations">false</bool>
|
||||||
|
|
||||||
<!-- The new animations to/from lockscreen and AOD! -->
|
|
||||||
<bool name="flag_lockscreen_animations">true</bool>
|
|
||||||
|
|
||||||
<!-- The new swipe to unlock animation, which shows the app/launcher behind the keyguard during
|
|
||||||
the swipe. -->
|
|
||||||
<bool name="flag_new_unlock_swipe_animation">true</bool>
|
|
||||||
|
|
||||||
<!-- The shared-element transition between lockscreen smartspace and launcher smartspace. -->
|
|
||||||
<bool name="flag_smartspace_shared_element_transition">false</bool>
|
|
||||||
|
|
||||||
<bool name="flag_pm_lite">true</bool>
|
|
||||||
|
|
||||||
<bool name="flag_charging_ripple">false</bool>
|
<bool name="flag_charging_ripple">false</bool>
|
||||||
|
|
||||||
<bool name="flag_ongoing_call_status_bar_chip">true</bool>
|
|
||||||
|
|
||||||
<bool name="flag_ongoing_call_in_immersive">true</bool>
|
|
||||||
|
|
||||||
<bool name="flag_ongoing_call_in_immersive_chip_tap">true</bool>
|
|
||||||
|
|
||||||
<bool name="flag_smartspace">false</bool>
|
<bool name="flag_smartspace">false</bool>
|
||||||
|
|
||||||
<bool name="flag_smartspace_deduping">true</bool>
|
|
||||||
|
|
||||||
<bool name="flag_combined_status_bar_signal_icons">false</bool>
|
|
||||||
|
|
||||||
<bool name="flag_new_user_switcher">true</bool>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import javax.inject.Inject;
|
|||||||
/**
|
/**
|
||||||
* Class to manage simple DeviceConfig-based feature flags.
|
* Class to manage simple DeviceConfig-based feature flags.
|
||||||
*
|
*
|
||||||
* See {@link FeatureFlagReader} for instructions on defining and flipping flags.
|
* See {@link Flags} for instructions on defining new flags.
|
||||||
*/
|
*/
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
public class FeatureFlags {
|
public class FeatureFlags {
|
||||||
@@ -87,67 +87,70 @@ public class FeatureFlags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNewNotifPipelineEnabled() {
|
public boolean isNewNotifPipelineEnabled() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2);
|
return isEnabled(Flags.NEW_NOTIFICATION_PIPELINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNewNotifPipelineRenderingEnabled() {
|
public boolean isNewNotifPipelineRenderingEnabled() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2_rendering);
|
return isEnabled(Flags.NEW_NOTIFICATION_PIPELINE_RENDERING);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
public boolean useNewLockscreenAnimations() {
|
public boolean useNewLockscreenAnimations() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations);
|
return isEnabled(Flags.LOCKSCREEN_ANIMATIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPeopleTileEnabled() {
|
public boolean isPeopleTileEnabled() {
|
||||||
|
// TODO(b/202860494): different resource overlays have different values.
|
||||||
return mFlagReader.isEnabled(R.bool.flag_conversations);
|
return mFlagReader.isEnabled(R.bool.flag_conversations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMonetEnabled() {
|
public boolean isMonetEnabled() {
|
||||||
|
// TODO(b/202860494): used in wallpaper picker. Always true, maybe delete.
|
||||||
return mFlagReader.isEnabled(R.bool.flag_monet);
|
return mFlagReader.isEnabled(R.bool.flag_monet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPMLiteEnabled() {
|
public boolean isPMLiteEnabled() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_pm_lite);
|
return isEnabled(Flags.POWER_MENU_LITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isChargingRippleEnabled() {
|
public boolean isChargingRippleEnabled() {
|
||||||
|
// TODO(b/202860494): different resource overlays have different values.
|
||||||
return mFlagReader.isEnabled(R.bool.flag_charging_ripple);
|
return mFlagReader.isEnabled(R.bool.flag_charging_ripple);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOngoingCallStatusBarChipEnabled() {
|
public boolean isOngoingCallStatusBarChipEnabled() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_ongoing_call_status_bar_chip);
|
return isEnabled(Flags.ONGOING_CALL_STATUS_BAR_CHIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOngoingCallInImmersiveEnabled() {
|
public boolean isOngoingCallInImmersiveEnabled() {
|
||||||
return isOngoingCallStatusBarChipEnabled()
|
return isOngoingCallStatusBarChipEnabled() && isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE);
|
||||||
&& mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOngoingCallInImmersiveChipTapEnabled() {
|
public boolean isOngoingCallInImmersiveChipTapEnabled() {
|
||||||
return isOngoingCallInImmersiveEnabled()
|
return isOngoingCallInImmersiveEnabled()
|
||||||
&& mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive_chip_tap);
|
&& isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSmartspaceEnabled() {
|
public boolean isSmartspaceEnabled() {
|
||||||
|
// TODO(b/202860494): different resource overlays have different values.
|
||||||
return mFlagReader.isEnabled(R.bool.flag_smartspace);
|
return mFlagReader.isEnabled(R.bool.flag_smartspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSmartspaceDedupingEnabled() {
|
public boolean isSmartspaceDedupingEnabled() {
|
||||||
return isSmartspaceEnabled() && mFlagReader.isEnabled(R.bool.flag_smartspace_deduping);
|
return isSmartspaceEnabled() && isEnabled(Flags.SMARTSPACE_DEDUPING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNewKeyguardSwipeAnimationEnabled() {
|
public boolean isNewKeyguardSwipeAnimationEnabled() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_new_unlock_swipe_animation);
|
return isEnabled(Flags.NEW_UNLOCK_SWIPE_ANIMATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSmartSpaceSharedElementTransitionEnabled() {
|
public boolean isSmartSpaceSharedElementTransitionEnabled() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_smartspace_shared_element_transition);
|
return isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether or not to use the provider model behavior for the status bar icons */
|
/** Whether or not to use the provider model behavior for the status bar icons */
|
||||||
public boolean isCombinedStatusBarSignalIconsEnabled() {
|
public boolean isCombinedStatusBarSignalIconsEnabled() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_combined_status_bar_signal_icons);
|
return isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** System setting for provider model behavior */
|
/** System setting for provider model behavior */
|
||||||
@@ -159,7 +162,7 @@ public class FeatureFlags {
|
|||||||
* Use the new version of the user switcher
|
* Use the new version of the user switcher
|
||||||
*/
|
*/
|
||||||
public boolean useNewUserSwitcher() {
|
public boolean useNewUserSwitcher() {
|
||||||
return mFlagReader.isEnabled(R.bool.flag_new_user_switcher);
|
return isEnabled(Flags.NEW_USER_SWITCHER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** static method for the system setting */
|
/** static method for the system setting */
|
||||||
|
|||||||
@@ -41,8 +41,11 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.FrameLayout.LayoutParams;
|
import android.widget.FrameLayout.LayoutParams;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.systemui.Dependency;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.animation.Interpolators;
|
import com.android.systemui.animation.Interpolators;
|
||||||
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||||
import com.android.systemui.statusbar.AlphaOptimizedImageView;
|
import com.android.systemui.statusbar.AlphaOptimizedImageView;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
@@ -306,7 +309,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
|
|||||||
final int showDismissSetting = Settings.Global.getInt(mContext.getContentResolver(),
|
final int showDismissSetting = Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
Settings.Global.SHOW_NEW_NOTIF_DISMISS, -1);
|
Settings.Global.SHOW_NEW_NOTIF_DISMISS, -1);
|
||||||
final boolean newFlowHideShelf = showDismissSetting == -1
|
final boolean newFlowHideShelf = showDismissSetting == -1
|
||||||
? mContext.getResources().getBoolean(R.bool.flag_notif_updates)
|
? Dependency.get(FeatureFlags.class).isEnabled(Flags.NOTIFICATION_UPDATES)
|
||||||
: showDismissSetting == 1;
|
: showDismissSetting == 1;
|
||||||
if (newFlowHideShelf) {
|
if (newFlowHideShelf) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import android.util.MathUtils;
|
|||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
import com.android.systemui.statusbar.notification.row.ExpandableView;
|
||||||
@@ -41,6 +43,7 @@ public class NotificationRoundnessManager {
|
|||||||
private final ExpandableView[] mTmpFirstInSectionViews;
|
private final ExpandableView[] mTmpFirstInSectionViews;
|
||||||
private final ExpandableView[] mTmpLastInSectionViews;
|
private final ExpandableView[] mTmpLastInSectionViews;
|
||||||
private final KeyguardBypassController mBypassController;
|
private final KeyguardBypassController mBypassController;
|
||||||
|
private final FeatureFlags mFeatureFlags;
|
||||||
private boolean mExpanded;
|
private boolean mExpanded;
|
||||||
private HashSet<ExpandableView> mAnimatedChildren;
|
private HashSet<ExpandableView> mAnimatedChildren;
|
||||||
private Runnable mRoundingChangedCallback;
|
private Runnable mRoundingChangedCallback;
|
||||||
@@ -55,7 +58,9 @@ public class NotificationRoundnessManager {
|
|||||||
@Inject
|
@Inject
|
||||||
NotificationRoundnessManager(
|
NotificationRoundnessManager(
|
||||||
KeyguardBypassController keyguardBypassController,
|
KeyguardBypassController keyguardBypassController,
|
||||||
NotificationSectionsFeatureManager sectionsFeatureManager) {
|
NotificationSectionsFeatureManager sectionsFeatureManager,
|
||||||
|
FeatureFlags featureFlags) {
|
||||||
|
mFeatureFlags = featureFlags;
|
||||||
int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
|
int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
|
||||||
mFirstInSectionViews = new ExpandableView[numberOfSections];
|
mFirstInSectionViews = new ExpandableView[numberOfSections];
|
||||||
mLastInSectionViews = new ExpandableView[numberOfSections];
|
mLastInSectionViews = new ExpandableView[numberOfSections];
|
||||||
@@ -122,9 +127,8 @@ public class NotificationRoundnessManager {
|
|||||||
void setViewsAffectedBySwipe(
|
void setViewsAffectedBySwipe(
|
||||||
ExpandableView viewBefore,
|
ExpandableView viewBefore,
|
||||||
ExpandableView viewSwiped,
|
ExpandableView viewSwiped,
|
||||||
ExpandableView viewAfter,
|
ExpandableView viewAfter) {
|
||||||
boolean cornerAnimationsEnabled) {
|
if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_UPDATES)) {
|
||||||
if (!cornerAnimationsEnabled) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final boolean animate = true;
|
final boolean animate = true;
|
||||||
|
|||||||
@@ -5311,10 +5311,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mController.getNoticationRoundessManager()
|
mController.getNoticationRoundessManager()
|
||||||
.setViewsAffectedBySwipe((ExpandableView) viewBefore,
|
.setViewsAffectedBySwipe(
|
||||||
|
(ExpandableView) viewBefore,
|
||||||
(ExpandableView) viewSwiped,
|
(ExpandableView) viewSwiped,
|
||||||
(ExpandableView) viewAfter,
|
(ExpandableView) viewAfter);
|
||||||
getResources().getBoolean(R.bool.flag_notif_updates));
|
|
||||||
|
|
||||||
updateFirstAndLastBackgroundViews();
|
updateFirstAndLastBackgroundViews();
|
||||||
requestDisallowInterceptTouchEvent(true);
|
requestDisallowInterceptTouchEvent(true);
|
||||||
@@ -5326,8 +5326,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
|||||||
void onSwipeEnd() {
|
void onSwipeEnd() {
|
||||||
updateFirstAndLastBackgroundViews();
|
updateFirstAndLastBackgroundViews();
|
||||||
mController.getNoticationRoundessManager()
|
mController.getNoticationRoundessManager()
|
||||||
.setViewsAffectedBySwipe(null, null, null,
|
.setViewsAffectedBySwipe(null, null, null);
|
||||||
getResources().getBoolean(R.bool.flag_notif_updates));
|
|
||||||
// Round bottom corners for notification right before shelf.
|
// Round bottom corners for notification right before shelf.
|
||||||
mShelf.updateAppearance();
|
mShelf.updateAppearance();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest;
|
|||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
||||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||||
@@ -61,6 +62,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
private ExpandableNotificationRow mSecond;
|
private ExpandableNotificationRow mSecond;
|
||||||
@Mock
|
@Mock
|
||||||
private KeyguardBypassController mBypassController;
|
private KeyguardBypassController mBypassController;
|
||||||
|
@Mock
|
||||||
|
private FeatureFlags mFeatureFlags;
|
||||||
private float mSmallRadiusRatio;
|
private float mSmallRadiusRatio;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -71,7 +74,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
|
|||||||
/ resources.getDimension(R.dimen.notification_corner_radius);
|
/ resources.getDimension(R.dimen.notification_corner_radius);
|
||||||
mRoundnessManager = new NotificationRoundnessManager(
|
mRoundnessManager = new NotificationRoundnessManager(
|
||||||
mBypassController,
|
mBypassController,
|
||||||
new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext));
|
new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext),
|
||||||
|
mFeatureFlags);
|
||||||
allowTestableLooperAsMainThread();
|
allowTestableLooperAsMainThread();
|
||||||
NotificationTestHelper testHelper = new NotificationTestHelper(
|
NotificationTestHelper testHelper = new NotificationTestHelper(
|
||||||
mContext,
|
mContext,
|
||||||
|
|||||||
Reference in New Issue
Block a user