Merge changes Ib37b1fbd,I799a0b80
* changes: Fix that accessibility shortcuts still turned but FM disappeared on the screen in owner mode after switching user. Fix didn’t update the strings immediately after language locale change.
This commit is contained in:
@@ -30,13 +30,21 @@ import static com.android.systemui.accessibility.floatingmenu.MenuViewAppearance
|
||||
|
||||
import android.annotation.FloatRange;
|
||||
import android.annotation.IntDef;
|
||||
import android.content.ComponentCallbacks;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.accessibility.dialog.AccessibilityTarget;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -50,6 +58,9 @@ import java.util.List;
|
||||
* Stores and observe the settings contents for the menu view.
|
||||
*/
|
||||
class MenuInfoRepository {
|
||||
private static final String TAG = "MenuInfoRepository";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Build.IS_DEBUGGABLE;
|
||||
|
||||
@FloatRange(from = 0.0, to = 1.0)
|
||||
private static final float DEFAULT_MENU_POSITION_X_PERCENT = 1.0f;
|
||||
|
||||
@@ -60,6 +71,10 @@ class MenuInfoRepository {
|
||||
private static final int DEFAULT_MIGRATION_TOOLTIP_VALUE_PROMPT = MigrationPrompt.DISABLED;
|
||||
|
||||
private final Context mContext;
|
||||
private final Configuration mConfiguration;
|
||||
private final AccessibilityManager mAccessibilityManager;
|
||||
private final AccessibilityManager.AccessibilityServicesStateChangeListener
|
||||
mA11yServicesStateChangeListener = manager -> onTargetFeaturesChanged();
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
private final OnSettingsContentsChanged mSettingsContentsCallback;
|
||||
private Position mPercentagePosition;
|
||||
@@ -74,12 +89,12 @@ class MenuInfoRepository {
|
||||
int ENABLED = 1;
|
||||
}
|
||||
|
||||
private final ContentObserver mMenuTargetFeaturesContentObserver =
|
||||
@VisibleForTesting
|
||||
final ContentObserver mMenuTargetFeaturesContentObserver =
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
mSettingsContentsCallback.onTargetFeaturesChanged(
|
||||
getTargets(mContext, ACCESSIBILITY_BUTTON));
|
||||
onTargetFeaturesChanged();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -102,8 +117,35 @@ class MenuInfoRepository {
|
||||
}
|
||||
};
|
||||
|
||||
MenuInfoRepository(Context context, OnSettingsContentsChanged settingsContentsChanged) {
|
||||
@VisibleForTesting
|
||||
final ComponentCallbacks mComponentCallbacks = new ComponentCallbacks() {
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
final int diff = newConfig.diff(mConfiguration);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onConfigurationChanged = " + Configuration.configurationDiffToString(
|
||||
diff));
|
||||
}
|
||||
|
||||
if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) {
|
||||
onTargetFeaturesChanged();
|
||||
}
|
||||
|
||||
mConfiguration.setTo(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
|
||||
MenuInfoRepository(Context context, AccessibilityManager accessibilityManager,
|
||||
OnSettingsContentsChanged settingsContentsChanged) {
|
||||
mContext = context;
|
||||
mAccessibilityManager = accessibilityManager;
|
||||
mConfiguration = new Configuration(context.getResources().getConfiguration());
|
||||
mSettingsContentsCallback = settingsContentsChanged;
|
||||
|
||||
mPercentagePosition = getStartPosition();
|
||||
@@ -172,6 +214,11 @@ class MenuInfoRepository {
|
||||
UserHandle.USER_CURRENT);
|
||||
}
|
||||
|
||||
private void onTargetFeaturesChanged() {
|
||||
mSettingsContentsCallback.onTargetFeaturesChanged(
|
||||
getTargets(mContext, ACCESSIBILITY_BUTTON));
|
||||
}
|
||||
|
||||
private Position getStartPosition() {
|
||||
final String absolutePositionString = Prefs.getString(mContext,
|
||||
Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, /* defaultValue= */ null);
|
||||
@@ -181,7 +228,7 @@ class MenuInfoRepository {
|
||||
: Position.fromString(absolutePositionString);
|
||||
}
|
||||
|
||||
void registerContentObservers() {
|
||||
void registerObserversAndCallbacks() {
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
|
||||
/* notifyForDescendants */ false, mMenuTargetFeaturesContentObserver,
|
||||
@@ -202,12 +249,20 @@ class MenuInfoRepository {
|
||||
Settings.Secure.getUriFor(ACCESSIBILITY_FLOATING_MENU_OPACITY),
|
||||
/* notifyForDescendants */ false, mMenuFadeOutContentObserver,
|
||||
UserHandle.USER_CURRENT);
|
||||
mContext.registerComponentCallbacks(mComponentCallbacks);
|
||||
|
||||
mAccessibilityManager.addAccessibilityServicesStateChangeListener(
|
||||
mA11yServicesStateChangeListener);
|
||||
}
|
||||
|
||||
void unregisterContentObservers() {
|
||||
void unregisterObserversAndCallbacks() {
|
||||
mContext.getContentResolver().unregisterContentObserver(mMenuTargetFeaturesContentObserver);
|
||||
mContext.getContentResolver().unregisterContentObserver(mMenuSizeContentObserver);
|
||||
mContext.getContentResolver().unregisterContentObserver(mMenuFadeOutContentObserver);
|
||||
mContext.unregisterComponentCallbacks(mComponentCallbacks);
|
||||
|
||||
mAccessibilityManager.removeAccessibilityServicesStateChangeListener(
|
||||
mA11yServicesStateChangeListener);
|
||||
}
|
||||
|
||||
interface OnSettingsContentsChanged {
|
||||
|
||||
@@ -299,7 +299,7 @@ class MenuView extends FrameLayout implements
|
||||
mMenuViewModel.getSizeTypeData().observeForever(mSizeTypeObserver);
|
||||
mMenuViewModel.getMoveToTuckedData().observeForever(mMoveToTuckedObserver);
|
||||
setVisibility(VISIBLE);
|
||||
mMenuViewModel.registerContentObservers();
|
||||
mMenuViewModel.registerObserversAndCallbacks();
|
||||
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
|
||||
getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater);
|
||||
}
|
||||
@@ -312,7 +312,7 @@ class MenuView extends FrameLayout implements
|
||||
mMenuViewModel.getTargetFeaturesData().removeObserver(mTargetFeaturesObserver);
|
||||
mMenuViewModel.getSizeTypeData().removeObserver(mSizeTypeObserver);
|
||||
mMenuViewModel.getMoveToTuckedData().removeObserver(mMoveToTuckedObserver);
|
||||
mMenuViewModel.unregisterContentObservers();
|
||||
mMenuViewModel.unregisterObserversAndCallbacks();
|
||||
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
|
||||
getViewTreeObserver().removeOnDrawListener(mSystemGestureExcludeUpdater);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class MenuViewLayer extends FrameLayout implements
|
||||
mAccessibilityManager = accessibilityManager;
|
||||
mFloatingMenu = floatingMenu;
|
||||
|
||||
mMenuViewModel = new MenuViewModel(context);
|
||||
mMenuViewModel = new MenuViewModel(context, accessibilityManager);
|
||||
mMenuViewAppearance = new MenuViewAppearance(context, windowManager);
|
||||
mMenuView = new MenuView(context, mMenuViewModel, mMenuViewAppearance);
|
||||
mMenuAnimationController = mMenuView.getMenuAnimationController();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.systemui.accessibility.floatingmenu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
@@ -41,8 +42,9 @@ class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged {
|
||||
private final MutableLiveData<Position> mPercentagePositionData = new MutableLiveData<>();
|
||||
private final MenuInfoRepository mInfoRepository;
|
||||
|
||||
MenuViewModel(Context context) {
|
||||
mInfoRepository = new MenuInfoRepository(context, /* settingsContentsChanged= */ this);
|
||||
MenuViewModel(Context context, AccessibilityManager accessibilityManager) {
|
||||
mInfoRepository = new MenuInfoRepository(context,
|
||||
accessibilityManager, /* settingsContentsChanged= */ this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,11 +113,11 @@ class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged {
|
||||
return mTargetFeaturesData;
|
||||
}
|
||||
|
||||
void registerContentObservers() {
|
||||
mInfoRepository.registerContentObservers();
|
||||
void registerObserversAndCallbacks() {
|
||||
mInfoRepository.registerObserversAndCallbacks();
|
||||
}
|
||||
|
||||
void unregisterContentObservers() {
|
||||
mInfoRepository.unregisterContentObservers();
|
||||
void unregisterObserversAndCallbacks() {
|
||||
mInfoRepository.unregisterObserversAndCallbacks();
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.verify;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -29,8 +30,12 @@ import com.android.systemui.SysuiTestCase;
|
||||
import com.android.wm.shell.bubbles.DismissView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Tests for {@link DismissAnimationController}. */
|
||||
@SmallTest
|
||||
@@ -40,10 +45,16 @@ public class DismissAnimationControllerTest extends SysuiTestCase {
|
||||
private DismissAnimationController mDismissAnimationController;
|
||||
private DismissView mDismissView;
|
||||
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager);
|
||||
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
|
||||
stubWindowManager);
|
||||
final MenuView stubMenuView = new MenuView(mContext, stubMenuViewModel,
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.testing.TestableLooper;
|
||||
import android.view.View;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.dynamicanimation.animation.DynamicAnimation;
|
||||
import androidx.dynamicanimation.animation.FlingAnimation;
|
||||
@@ -43,9 +44,13 @@ import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -61,12 +66,18 @@ public class MenuAnimationControllerTest extends SysuiTestCase {
|
||||
private MenuView mMenuView;
|
||||
private TestMenuAnimationController mMenuAnimationController;
|
||||
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
|
||||
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
|
||||
stubWindowManager);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager);
|
||||
|
||||
mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance));
|
||||
mViewPropertyAnimator = spy(mMenuView.animate());
|
||||
|
||||
@@ -16,16 +16,23 @@
|
||||
|
||||
package com.android.systemui.accessibility.floatingmenu;
|
||||
|
||||
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -34,6 +41,10 @@ import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/** Tests for {@link MenuInfoRepository}. */
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@SmallTest
|
||||
@@ -41,14 +52,29 @@ public class MenuInfoRepositoryTest extends SysuiTestCase {
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
|
||||
@Mock
|
||||
private MenuInfoRepository.OnSettingsContentsChanged mMockSettingsContentsChanged;
|
||||
|
||||
private MenuInfoRepository mMenuInfoRepository;
|
||||
private final List<String> mShortcutTargets = new ArrayList<>();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mMenuInfoRepository = new MenuInfoRepository(mContext, mMockSettingsContentsChanged);
|
||||
mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
|
||||
mShortcutTargets.add(MAGNIFICATION_CONTROLLER_NAME);
|
||||
doReturn(mShortcutTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets(
|
||||
anyInt());
|
||||
|
||||
mMenuInfoRepository = new MenuInfoRepository(mContext, mAccessibilityManager,
|
||||
mMockSettingsContentsChanged);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mShortcutTargets.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -64,4 +90,14 @@ public class MenuInfoRepositoryTest extends SysuiTestCase {
|
||||
|
||||
verify(mMockSettingsContentsChanged).onFadeEffectInfoChanged(any(MenuFadeEffectInfo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void localeChange_verifyTargetFeaturesChanged() {
|
||||
final Configuration configuration = new Configuration();
|
||||
configuration.setLocale(Locale.TAIWAN);
|
||||
|
||||
mMenuInfoRepository.mComponentCallbacks.onConfigurationChanged(configuration);
|
||||
|
||||
verify(mMockSettingsContentsChanged).onTargetFeaturesChanged(any());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.graphics.Rect;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
@@ -55,6 +56,9 @@ public class MenuItemAccessibilityDelegateTest extends SysuiTestCase {
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
|
||||
@Mock
|
||||
private DismissAnimationController.DismissCallback mStubDismissCallback;
|
||||
|
||||
@@ -69,7 +73,7 @@ public class MenuItemAccessibilityDelegateTest extends SysuiTestCase {
|
||||
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
|
||||
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
|
||||
stubWindowManager);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager);
|
||||
|
||||
final int halfScreenHeight =
|
||||
stubWindowManager.getCurrentWindowMetrics().getBounds().height() / 2;
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.test.filters.SmallTest;
|
||||
@@ -42,8 +43,12 @@ import com.android.wm.shell.bubbles.DismissView;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -64,10 +69,16 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase {
|
||||
private RecyclerView mStubListView;
|
||||
private DismissView mDismissView;
|
||||
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager);
|
||||
final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
|
||||
windowManager);
|
||||
mStubMenuView = new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance);
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.graphics.drawable.GradientDrawable;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.WindowManager;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
@@ -37,8 +38,12 @@ import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Tests for {@link MenuView}. */
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@@ -52,12 +57,18 @@ public class MenuViewTest extends SysuiTestCase {
|
||||
private String mLastPosition;
|
||||
private MenuViewAppearance mStubMenuViewAppearance;
|
||||
|
||||
@Rule
|
||||
public MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mUiModeManager = mContext.getSystemService(UiModeManager.class);
|
||||
mNightMode = mUiModeManager.getNightMode();
|
||||
mUiModeManager.setNightMode(MODE_NIGHT_YES);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext);
|
||||
final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager);
|
||||
final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
|
||||
mStubMenuViewAppearance = new MenuViewAppearance(mContext, stubWindowManager);
|
||||
mMenuView = spy(new MenuView(mContext, stubMenuViewModel, mStubMenuViewAppearance));
|
||||
|
||||
Reference in New Issue
Block a user