[DO NOT MERGE] Do not dismiss keyguard after SIM PUK unlock
After PUK unlock, multiple calls to
KeyguardSecurityContainerController#dismiss() were being called from
the KeyguardSimPukViewController, which begins the transition to the
next security screen, if any. At the same time, other parts of the
system, also listening to SIM events, recognize the PUK unlock and
call KeyguardSecurityContainer#showSecurityScreen, which updates which
security method comes next. After boot, this should be one of PIN,
Password, Pattern, assuming they have a security method. If one of the
first dismiss() calls comes AFTER the security method changes, this is
incorrectly recognized by the code as a successful
PIN/pattern/password unlock. This causes the keyguard to be marked as
done, causing screen flickers and incorrect system state.
The solution: every call to dismiss() should include a new parameter
for the security method used. If there is a difference between this
parameter and the current value in KeyguardSecurityContainerCallback,
ignore the request, as the system state has changed.
Fixes: 238804980
Bug: 218500036
Test: atest KeyguardSecurityContainerTest
AdminSecondaryLockScreenControllerTest KeyguardHostViewControllerTest
KeyguardSecurityContainerControllerTest
Change-Id: I7c8714a177bc85fbce92f6e8fe911f74ca2ac243
Merged-In: I7c8714a177bc85fbce92f6e8fe911f74ca2ac243
(cherry picked from commit 37aeb26b0a)
This commit is contained in:
@@ -33,6 +33,7 @@ import android.view.SurfaceView;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||||
import com.android.keyguard.dagger.KeyguardBouncerScope;
|
import com.android.keyguard.dagger.KeyguardBouncerScope;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
|
|
||||||
@@ -208,7 +209,7 @@ public class AdminSecondaryLockScreenController {
|
|||||||
hide();
|
hide();
|
||||||
if (mKeyguardCallback != null) {
|
if (mKeyguardCallback != null) {
|
||||||
mKeyguardCallback.dismiss(/* securityVerified= */ true, userId,
|
mKeyguardCallback.dismiss(/* securityVerified= */ true, userId,
|
||||||
/* bypassSecondaryLockScreen= */true);
|
/* bypassSecondaryLockScreen= */true, SecurityMode.Invalid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
|
|||||||
if (dismissKeyguard) {
|
if (dismissKeyguard) {
|
||||||
mDismissing = true;
|
mDismissing = true;
|
||||||
mLatencyTracker.onActionStart(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);
|
mLatencyTracker.onActionStart(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);
|
||||||
getKeyguardSecurityCallback().dismiss(true, userId);
|
getKeyguardSecurityCallback().dismiss(true, userId, getSecurityMode());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isValidPassword) {
|
if (isValidPassword) {
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
|
|||||||
Log.i(TAG, "TrustAgent dismissed Keyguard.");
|
Log.i(TAG, "TrustAgent dismissed Keyguard.");
|
||||||
}
|
}
|
||||||
mSecurityCallback.dismiss(false /* authenticated */, userId,
|
mSecurityCallback.dismiss(false /* authenticated */, userId,
|
||||||
/* bypassSecondaryLockScreen */ false);
|
/* bypassSecondaryLockScreen */ false, SecurityMode.Invalid);
|
||||||
} else {
|
} else {
|
||||||
mViewMediatorCallback.playTrustedSound();
|
mViewMediatorCallback.playTrustedSound();
|
||||||
}
|
}
|
||||||
@@ -105,9 +105,9 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dismiss(boolean authenticated, int targetUserId,
|
public boolean dismiss(boolean authenticated, int targetUserId,
|
||||||
boolean bypassSecondaryLockScreen) {
|
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
|
||||||
return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
|
return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
|
||||||
authenticated, targetUserId, bypassSecondaryLockScreen);
|
authenticated, targetUserId, bypassSecondaryLockScreen, expectedSecurityMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -215,7 +215,8 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
|
|||||||
* @return True if the keyguard is done.
|
* @return True if the keyguard is done.
|
||||||
*/
|
*/
|
||||||
public boolean dismiss(int targetUserId) {
|
public boolean dismiss(int targetUserId) {
|
||||||
return mSecurityCallback.dismiss(false, targetUserId, false);
|
return mSecurityCallback.dismiss(false, targetUserId, false,
|
||||||
|
getCurrentSecurityMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -356,10 +357,10 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean handleBackKey() {
|
public boolean handleBackKey() {
|
||||||
if (mKeyguardSecurityContainerController.getCurrentSecurityMode()
|
SecurityMode securityMode = mKeyguardSecurityContainerController.getCurrentSecurityMode();
|
||||||
!= SecurityMode.None) {
|
if (securityMode != SecurityMode.None) {
|
||||||
mKeyguardSecurityContainerController.dismiss(
|
mKeyguardSecurityContainerController.dismiss(
|
||||||
false, KeyguardUpdateMonitor.getCurrentUser());
|
false, KeyguardUpdateMonitor.getCurrentUser(), securityMode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -59,10 +59,11 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void dismiss(boolean securityVerified, int targetUserId) { }
|
public void dismiss(boolean securityVerified, int targetUserId,
|
||||||
|
SecurityMode expectedSecurityMode) { }
|
||||||
@Override
|
@Override
|
||||||
public void dismiss(boolean authenticated, int targetId,
|
public void dismiss(boolean authenticated, int targetId,
|
||||||
boolean bypassSecondaryLockScreen) { }
|
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { }
|
||||||
@Override
|
@Override
|
||||||
public void onUserInput() { }
|
public void onUserInput() { }
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ public class KeyguardPatternViewController
|
|||||||
if (dismissKeyguard) {
|
if (dismissKeyguard) {
|
||||||
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
|
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
|
||||||
mLatencyTracker.onActionStart(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);
|
mLatencyTracker.onActionStart(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);
|
||||||
getKeyguardSecurityCallback().dismiss(true, userId);
|
getKeyguardSecurityCallback().dismiss(true, userId, SecurityMode.Pattern);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
|
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
|
||||||
|
|||||||
@@ -15,14 +15,17 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.keyguard;
|
package com.android.keyguard;
|
||||||
|
|
||||||
|
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||||
|
|
||||||
public interface KeyguardSecurityCallback {
|
public interface KeyguardSecurityCallback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dismiss the given security screen.
|
* Dismiss the given security screen.
|
||||||
* @param securityVerified true if the user correctly entered credentials for the given screen.
|
* @param securityVerified true if the user correctly entered credentials for the given screen.
|
||||||
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
|
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
|
||||||
|
* @param expectedSecurityMode The security mode that is invoking this dismiss.
|
||||||
*/
|
*/
|
||||||
void dismiss(boolean securityVerified, int targetUserId);
|
void dismiss(boolean securityVerified, int targetUserId, SecurityMode expectedSecurityMode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dismiss the given security screen.
|
* Dismiss the given security screen.
|
||||||
@@ -30,8 +33,10 @@ public interface KeyguardSecurityCallback {
|
|||||||
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
|
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
|
||||||
* @param bypassSecondaryLockScreen true if the user can bypass the secondary lock screen,
|
* @param bypassSecondaryLockScreen true if the user can bypass the secondary lock screen,
|
||||||
* if any, during this dismissal.
|
* if any, during this dismissal.
|
||||||
|
* @param expectedSecurityMode The security mode that is invoking this dismiss.
|
||||||
*/
|
*/
|
||||||
void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen);
|
void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen,
|
||||||
|
SecurityMode expectedSecurityMode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manually report user activity to keep the device awake.
|
* Manually report user activity to keep the device awake.
|
||||||
|
|||||||
@@ -181,7 +181,12 @@ public class KeyguardSecurityContainer extends FrameLayout {
|
|||||||
|
|
||||||
// Used to notify the container when something interesting happens.
|
// Used to notify the container when something interesting happens.
|
||||||
public interface SecurityCallback {
|
public interface SecurityCallback {
|
||||||
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
|
/**
|
||||||
|
* Potentially dismiss the current security screen, after validating that all device
|
||||||
|
* security has been unlocked. Otherwise show the next screen.
|
||||||
|
*/
|
||||||
|
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen,
|
||||||
|
SecurityMode expectedSecurityMode);
|
||||||
|
|
||||||
void userActivity();
|
void userActivity();
|
||||||
|
|
||||||
|
|||||||
@@ -136,14 +136,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dismiss(boolean authenticated, int targetId) {
|
public void dismiss(boolean authenticated, int targetId,
|
||||||
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
|
SecurityMode expectedSecurityMode) {
|
||||||
|
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false,
|
||||||
|
expectedSecurityMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dismiss(boolean authenticated, int targetId,
|
public void dismiss(boolean authenticated, int targetId,
|
||||||
boolean bypassSecondaryLockScreen) {
|
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
|
||||||
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
|
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen,
|
||||||
|
expectedSecurityMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVerifyUnlockOnly() {
|
public boolean isVerifyUnlockOnly() {
|
||||||
@@ -307,8 +310,13 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
|||||||
return mCurrentSecurityMode;
|
return mCurrentSecurityMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dismiss(boolean authenticated, int targetUserId) {
|
/**
|
||||||
mKeyguardSecurityCallback.dismiss(authenticated, targetUserId);
|
* Potentially dismiss the current security screen, after validating that all device
|
||||||
|
* security has been unlocked. Otherwise show the next screen.
|
||||||
|
*/
|
||||||
|
public void dismiss(boolean authenticated, int targetUserId,
|
||||||
|
SecurityMode expectedSecurityMode) {
|
||||||
|
mKeyguardSecurityCallback.dismiss(authenticated, targetUserId, expectedSecurityMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
@@ -367,12 +375,21 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
|
|||||||
* completion.
|
* completion.
|
||||||
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
|
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
|
||||||
* secondary lock screen requirement, if any.
|
* secondary lock screen requirement, if any.
|
||||||
|
* @param expectedSecurityMode SecurityMode that is invoking this request. SecurityMode.Invalid
|
||||||
|
* indicates that no check should be done
|
||||||
* @return true if keyguard is done
|
* @return true if keyguard is done
|
||||||
*/
|
*/
|
||||||
public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
|
public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
|
||||||
boolean bypassSecondaryLockScreen) {
|
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
|
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
|
||||||
|
if (expectedSecurityMode != SecurityMode.Invalid
|
||||||
|
&& expectedSecurityMode != getCurrentSecurityMode()) {
|
||||||
|
Log.w(TAG, "Attempted to invoke showNextSecurityScreenOrFinish with securityMode "
|
||||||
|
+ expectedSecurityMode + ", but current mode is " + getCurrentSecurityMode());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
boolean finish = false;
|
boolean finish = false;
|
||||||
boolean strongAuth = false;
|
boolean strongAuth = false;
|
||||||
int eventSubtype = -1;
|
int eventSubtype = -1;
|
||||||
|
|||||||
@@ -162,7 +162,8 @@ public class KeyguardSimPinViewController
|
|||||||
mRemainingAttempts = -1;
|
mRemainingAttempts = -1;
|
||||||
mShowDefaultMessage = true;
|
mShowDefaultMessage = true;
|
||||||
getKeyguardSecurityCallback().dismiss(
|
getKeyguardSecurityCallback().dismiss(
|
||||||
true, KeyguardUpdateMonitor.getCurrentUser());
|
true, KeyguardUpdateMonitor.getCurrentUser(),
|
||||||
|
SecurityMode.SimPin);
|
||||||
} else {
|
} else {
|
||||||
mShowDefaultMessage = false;
|
mShowDefaultMessage = false;
|
||||||
if (result.getResult() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
|
if (result.getResult() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ public class KeyguardSimPukViewController
|
|||||||
if (simState == TelephonyManager.SIM_STATE_READY) {
|
if (simState == TelephonyManager.SIM_STATE_READY) {
|
||||||
mRemainingAttempts = -1;
|
mRemainingAttempts = -1;
|
||||||
mShowDefaultMessage = true;
|
mShowDefaultMessage = true;
|
||||||
getKeyguardSecurityCallback().dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
|
getKeyguardSecurityCallback().dismiss(true, KeyguardUpdateMonitor.getCurrentUser(),
|
||||||
|
SecurityMode.SimPuk);
|
||||||
} else {
|
} else {
|
||||||
resetState();
|
resetState();
|
||||||
}
|
}
|
||||||
@@ -274,7 +275,8 @@ public class KeyguardSimPukViewController
|
|||||||
mShowDefaultMessage = true;
|
mShowDefaultMessage = true;
|
||||||
|
|
||||||
getKeyguardSecurityCallback().dismiss(
|
getKeyguardSecurityCallback().dismiss(
|
||||||
true, KeyguardUpdateMonitor.getCurrentUser());
|
true, KeyguardUpdateMonitor.getCurrentUser(),
|
||||||
|
SecurityMode.SimPuk);
|
||||||
} else {
|
} else {
|
||||||
mShowDefaultMessage = false;
|
mShowDefaultMessage = false;
|
||||||
if (result.getResult() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
|
if (result.getResult() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import android.view.SurfaceView;
|
|||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -190,7 +191,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
private void verifyViewDismissed(SurfaceView v) throws Exception {
|
private void verifyViewDismissed(SurfaceView v) throws Exception {
|
||||||
verify(mKeyguardSecurityContainer).removeView(v);
|
verify(mKeyguardSecurityContainer).removeView(v);
|
||||||
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true);
|
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true, SecurityMode.Invalid);
|
||||||
assertThat(mContext.isBound(mComponentName)).isFalse();
|
assertThat(mContext.isBound(mComponentName)).isFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package com.android.keyguard;
|
|||||||
|
|
||||||
import static android.view.WindowInsets.Type.ime;
|
import static android.view.WindowInsets.Type.ime;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
@@ -63,6 +65,7 @@ import org.mockito.junit.MockitoRule;
|
|||||||
@TestableLooper.RunWithLooper()
|
@TestableLooper.RunWithLooper()
|
||||||
public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
||||||
private static final int VIEW_WIDTH = 1600;
|
private static final int VIEW_WIDTH = 1600;
|
||||||
|
private static final int TARGET_USER_ID = 100;
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public MockitoRule mRule = MockitoJUnit.rule();
|
public MockitoRule mRule = MockitoJUnit.rule();
|
||||||
@@ -330,4 +333,42 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
|
|||||||
R.bool.can_use_one_handed_bouncer))
|
R.bool.can_use_one_handed_bouncer))
|
||||||
.thenReturn(sysuiResourceCanUseOneHandedKeyguard);
|
.thenReturn(sysuiResourceCanUseOneHandedKeyguard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void showNextSecurityScreenOrFinish_setsSecurityScreenToPinAfterSimPinUnlock() {
|
||||||
|
// GIVEN the current security method is SimPin
|
||||||
|
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
|
||||||
|
when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID)).thenReturn(false);
|
||||||
|
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.SimPin);
|
||||||
|
|
||||||
|
// WHEN a request is made from the SimPin screens to show the next security method
|
||||||
|
when(mKeyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.PIN);
|
||||||
|
mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
|
||||||
|
/* authenticated= */true,
|
||||||
|
TARGET_USER_ID,
|
||||||
|
/* bypassSecondaryLockScreen= */true,
|
||||||
|
SecurityMode.SimPin);
|
||||||
|
|
||||||
|
// THEN the next security method of PIN is set, and the keyguard is not marked as done
|
||||||
|
verify(mSecurityCallback, never()).finish(anyBoolean(), anyInt());
|
||||||
|
assertThat(mKeyguardSecurityContainerController.getCurrentSecurityMode())
|
||||||
|
.isEqualTo(SecurityMode.PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void showNextSecurityScreenOrFinish_ignoresCallWhenSecurityMethodHasChanged() {
|
||||||
|
//GIVEN current security mode has been set to PIN
|
||||||
|
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.PIN);
|
||||||
|
|
||||||
|
//WHEN a request comes from SimPin to dismiss the security screens
|
||||||
|
boolean keyguardDone = mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
|
||||||
|
/* authenticated= */true,
|
||||||
|
TARGET_USER_ID,
|
||||||
|
/* bypassSecondaryLockScreen= */true,
|
||||||
|
SecurityMode.SimPin);
|
||||||
|
|
||||||
|
//THEN no action has happened, which will not dismiss the security screens
|
||||||
|
assertThat(keyguardDone).isEqualTo(false);
|
||||||
|
verify(mKeyguardUpdateMonitor, never()).getUserHasTrust(anyInt());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user