Remove all GHBM logic
Removing GHBM logic from codebase since it has been replaced by LHBM. This will simplify the current implementation, and assist with future refactors and the transition to Kotlin. Fixes: 227229729 Test: atest UdfpsViewTest Test: atest DisplayModeDirectorTest Change-Id: I0d1e7ffb610154f4d56afab8385883a0389f89db
This commit is contained in:
@@ -24,31 +24,20 @@ package android.hardware.fingerprint;
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IUdfpsHbmListener {
|
||||
|
||||
/** HBM that applies to the whole screen. */
|
||||
const int GLOBAL_HBM = 0;
|
||||
|
||||
/** HBM that only applies to a portion of the screen. */
|
||||
const int LOCAL_HBM = 1;
|
||||
|
||||
/**
|
||||
* UdfpsController will call this method when the HBM is enabled.
|
||||
*
|
||||
* @param hbmType The type of HBM that was enabled. See
|
||||
* {@link com.android.systemui.biometrics.UdfpsHbmTypes}.
|
||||
* @param displayId The displayId for which the HBM is enabled. See
|
||||
* {@link android.view.Display#getDisplayId()}.
|
||||
*/
|
||||
void onHbmEnabled(int hbmType, int displayId);
|
||||
void onHbmEnabled(int displayId);
|
||||
|
||||
/**
|
||||
* UdfpsController will call this method when the HBM is disabled.
|
||||
*
|
||||
* @param hbmType The type of HBM that was disabled. See
|
||||
* {@link com.android.systemui.biometrics.UdfpsHbmTypes}.
|
||||
* @param displayId The displayId for which the HBM is disabled. See
|
||||
* {@link android.view.Display#getDisplayId()}.
|
||||
*/
|
||||
void onHbmDisabled(int hbmType, int displayId);
|
||||
void onHbmDisabled(int displayId);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,4 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<com.android.systemui.biometrics.UdfpsSurfaceView
|
||||
android:id="@+id/hbm_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible"/>
|
||||
|
||||
</com.android.systemui.biometrics.UdfpsView>
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
package com.android.systemui.biometrics;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.android.systemui.biometrics.UdfpsHbmTypes.HbmType;
|
||||
|
||||
/**
|
||||
* Interface for controlling the high-brightness mode (HBM). UdfpsView can use this callback to
|
||||
@@ -36,24 +33,21 @@ public interface UdfpsHbmProvider {
|
||||
* This method must be called from the UI thread. The callback, if provided, will also be
|
||||
* invoked from the UI thread.
|
||||
*
|
||||
* @param hbmType The type of HBM that should be enabled. See {@link UdfpsHbmTypes}.
|
||||
* @param surface The surface for which the HBM is requested, in case the HBM implementation
|
||||
* needs to set special surface flags to enable the HBM. Can be null.
|
||||
* @param onHbmEnabled A runnable that will be executed once HBM is enabled.
|
||||
*/
|
||||
void enableHbm(@HbmType int hbmType, @Nullable Surface surface,
|
||||
@Nullable Runnable onHbmEnabled);
|
||||
void enableHbm(@Nullable Runnable onHbmEnabled);
|
||||
|
||||
/**
|
||||
* UdfpsView will call this to disable the HBM when the illumination is not longer needed.
|
||||
* UdfpsView will call this to disable HBM when illumination is no longer needed.
|
||||
*
|
||||
* This method is a no-op when HBM is already disabled. If HBM is enabled, this method will
|
||||
* disable HBM for the {@code hbmType} and {@code surface} that were provided to the
|
||||
* corresponding {@link #enableHbm(int, Surface, Runnable)}.
|
||||
* This method will disable HBM if HBM is enabled. Otherwise, if HBM is already disabled,
|
||||
* this method is a no-op.
|
||||
*
|
||||
* The call must be made from the UI thread. The callback, if provided, will also be invoked
|
||||
* from the UI thread.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param onHbmDisabled A runnable that will be executed once HBM is disabled.
|
||||
*/
|
||||
void disableHbm(@Nullable Runnable onHbmDisabled);
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.biometrics;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.hardware.fingerprint.IUdfpsHbmListener;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Different high-brightness mode (HBM) types that are relevant to this package.
|
||||
*/
|
||||
public final class UdfpsHbmTypes {
|
||||
/** HBM that applies to the whole screen. */
|
||||
public static final int GLOBAL_HBM = IUdfpsHbmListener.GLOBAL_HBM;
|
||||
|
||||
/** HBM that only applies to a portion of the screen. */
|
||||
public static final int LOCAL_HBM = IUdfpsHbmListener.LOCAL_HBM;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({GLOBAL_HBM, LOCAL_HBM})
|
||||
public @interface HbmType {
|
||||
}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.biometrics;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
/**
|
||||
* Surface View for providing the Global High-Brightness Mode (GHBM) illumination for UDFPS.
|
||||
*/
|
||||
public class UdfpsSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
private static final String TAG = "UdfpsSurfaceView";
|
||||
|
||||
/**
|
||||
* Notifies {@link UdfpsView} when to enable GHBM illumination.
|
||||
*/
|
||||
interface GhbmIlluminationListener {
|
||||
/**
|
||||
* @param surface the surface for which GHBM should be enabled.
|
||||
* @param onIlluminatedRunnable a runnable that should be run after GHBM is enabled.
|
||||
*/
|
||||
void enableGhbm(@NonNull Surface surface, @Nullable Runnable onIlluminatedRunnable);
|
||||
}
|
||||
|
||||
@NonNull private final SurfaceHolder mHolder;
|
||||
@NonNull private final Paint mSensorPaint;
|
||||
|
||||
@Nullable private GhbmIlluminationListener mGhbmIlluminationListener;
|
||||
@Nullable private Runnable mOnIlluminatedRunnable;
|
||||
boolean mAwaitingSurfaceToStartIllumination;
|
||||
boolean mHasValidSurface;
|
||||
|
||||
public UdfpsSurfaceView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
// Make this SurfaceView draw on top of everything else in this window. This allows us to
|
||||
// 1) Always show the HBM circle on top of everything else, and
|
||||
// 2) Properly composite this view with any other animations in the same window no matter
|
||||
// what contents are added in which order to this view hierarchy.
|
||||
setZOrderOnTop(true);
|
||||
|
||||
mHolder = getHolder();
|
||||
mHolder.addCallback(this);
|
||||
mHolder.setFormat(PixelFormat.RGBA_8888);
|
||||
|
||||
mSensorPaint = new Paint(0 /* flags */);
|
||||
mSensorPaint.setAntiAlias(true);
|
||||
mSensorPaint.setARGB(255, 255, 255, 255);
|
||||
mSensorPaint.setStyle(Paint.Style.FILL);
|
||||
}
|
||||
|
||||
@Override public void surfaceCreated(SurfaceHolder holder) {
|
||||
mHasValidSurface = true;
|
||||
if (mAwaitingSurfaceToStartIllumination) {
|
||||
doIlluminate(mOnIlluminatedRunnable);
|
||||
mOnIlluminatedRunnable = null;
|
||||
mAwaitingSurfaceToStartIllumination = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
// Unused.
|
||||
}
|
||||
|
||||
@Override public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
mHasValidSurface = false;
|
||||
}
|
||||
|
||||
void setGhbmIlluminationListener(@Nullable GhbmIlluminationListener listener) {
|
||||
mGhbmIlluminationListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: there is no corresponding method to stop GHBM illumination. It is expected that
|
||||
* {@link UdfpsView} will hide this view, which would destroy the surface and remove the
|
||||
* illumination dot.
|
||||
*/
|
||||
void startGhbmIllumination(@Nullable Runnable onIlluminatedRunnable) {
|
||||
if (mGhbmIlluminationListener == null) {
|
||||
Log.e(TAG, "startIllumination | mGhbmIlluminationListener is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHasValidSurface) {
|
||||
doIlluminate(onIlluminatedRunnable);
|
||||
} else {
|
||||
mAwaitingSurfaceToStartIllumination = true;
|
||||
mOnIlluminatedRunnable = onIlluminatedRunnable;
|
||||
}
|
||||
}
|
||||
|
||||
private void doIlluminate(@Nullable Runnable onIlluminatedRunnable) {
|
||||
if (mGhbmIlluminationListener == null) {
|
||||
Log.e(TAG, "doIlluminate | mGhbmIlluminationListener is null");
|
||||
return;
|
||||
}
|
||||
|
||||
mGhbmIlluminationListener.enableGhbm(mHolder.getSurface(), onIlluminatedRunnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately draws the illumination dot on this SurfaceView's surface.
|
||||
*/
|
||||
void drawIlluminationDot(@NonNull RectF sensorRect) {
|
||||
if (!mHasValidSurface) {
|
||||
Log.e(TAG, "drawIlluminationDot | the surface is destroyed or was never created.");
|
||||
return;
|
||||
}
|
||||
Canvas canvas = null;
|
||||
try {
|
||||
canvas = mHolder.lockCanvas();
|
||||
canvas.drawOval(sensorRect, mSensorPaint);
|
||||
} finally {
|
||||
// Make sure the surface is never left in a bad state.
|
||||
if (canvas != null) {
|
||||
mHolder.unlockCanvasAndPost(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,26 +22,17 @@ import android.graphics.Paint
|
||||
import android.graphics.PointF
|
||||
import android.graphics.RectF
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||
import android.os.Build
|
||||
import android.os.UserHandle
|
||||
import android.provider.Settings
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.MotionEvent
|
||||
import android.view.Surface
|
||||
import android.widget.FrameLayout
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.doze.DozeReceiver
|
||||
import com.android.systemui.biometrics.UdfpsHbmTypes.HbmType
|
||||
|
||||
private const val TAG = "UdfpsView"
|
||||
private const val SETTING_HBM_TYPE = "com.android.systemui.biometrics.UdfpsSurfaceView.hbmType"
|
||||
@HbmType
|
||||
private const val DEFAULT_HBM_TYPE = UdfpsHbmTypes.LOCAL_HBM
|
||||
|
||||
/**
|
||||
* A view containing 1) A SurfaceView for HBM, and 2) A normal drawable view for all other
|
||||
* animations.
|
||||
* The main view group containing all UDFPS animations.
|
||||
*/
|
||||
class UdfpsView(
|
||||
context: Context,
|
||||
@@ -68,21 +59,6 @@ class UdfpsView(
|
||||
com.android.internal.R.integer.config_udfps_illumination_transition_ms
|
||||
).toLong()
|
||||
|
||||
@HbmType
|
||||
private val hbmType = if (Build.IS_ENG || Build.IS_USERDEBUG) {
|
||||
Settings.Secure.getIntForUser(
|
||||
context.contentResolver,
|
||||
SETTING_HBM_TYPE,
|
||||
DEFAULT_HBM_TYPE,
|
||||
UserHandle.USER_CURRENT
|
||||
)
|
||||
} else {
|
||||
DEFAULT_HBM_TYPE
|
||||
}
|
||||
|
||||
// Only used for UdfpsHbmTypes.GLOBAL_HBM.
|
||||
private var ghbmView: UdfpsSurfaceView? = null
|
||||
|
||||
/** View controller (can be different for enrollment, BiometricPrompt, Keyguard, etc.). */
|
||||
var animationViewController: UdfpsAnimationViewController<*>? = null
|
||||
|
||||
@@ -109,12 +85,6 @@ class UdfpsView(
|
||||
return (animationViewController == null || !animationViewController!!.shouldPauseAuth())
|
||||
}
|
||||
|
||||
override fun onFinishInflate() {
|
||||
if (hbmType == UdfpsHbmTypes.GLOBAL_HBM) {
|
||||
ghbmView = findViewById(R.id.hbm_view)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dozeTimeTick() {
|
||||
animationViewController?.dozeTimeTick()
|
||||
}
|
||||
@@ -180,24 +150,11 @@ class UdfpsView(
|
||||
override fun startIllumination(onIlluminatedRunnable: Runnable?) {
|
||||
isIlluminationRequested = true
|
||||
animationViewController?.onIlluminationStarting()
|
||||
|
||||
val gView = ghbmView
|
||||
if (gView != null) {
|
||||
gView.setGhbmIlluminationListener(this::doIlluminate)
|
||||
gView.visibility = VISIBLE
|
||||
gView.startGhbmIllumination(onIlluminatedRunnable)
|
||||
} else {
|
||||
doIlluminate(null /* surface */, onIlluminatedRunnable)
|
||||
}
|
||||
doIlluminate(onIlluminatedRunnable)
|
||||
}
|
||||
|
||||
private fun doIlluminate(surface: Surface?, onIlluminatedRunnable: Runnable?) {
|
||||
if (ghbmView != null && surface == null) {
|
||||
Log.e(TAG, "doIlluminate | surface must be non-null for GHBM")
|
||||
}
|
||||
|
||||
hbmProvider?.enableHbm(hbmType, surface) {
|
||||
ghbmView?.drawIlluminationDot(sensorRect)
|
||||
private fun doIlluminate(onIlluminatedRunnable: Runnable?) {
|
||||
hbmProvider?.enableHbm() {
|
||||
if (onIlluminatedRunnable != null) {
|
||||
// No framework API can reliably tell when a frame reaches the panel. A timeout
|
||||
// is the safest solution.
|
||||
@@ -211,10 +168,6 @@ class UdfpsView(
|
||||
override fun stopIllumination() {
|
||||
isIlluminationRequested = false
|
||||
animationViewController?.onIlluminationStopped()
|
||||
ghbmView?.let { view ->
|
||||
view.setGhbmIlluminationListener(null)
|
||||
view.visibility = INVISIBLE
|
||||
}
|
||||
hbmProvider?.disableHbm(null /* onHbmDisabled */)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.testing.ViewUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Surface
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
@@ -37,7 +36,6 @@ import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.nullable
|
||||
import org.mockito.Mockito.verify
|
||||
@@ -148,7 +146,7 @@ class UdfpsViewTest : SysuiTestCase() {
|
||||
view.startIllumination(onDone)
|
||||
|
||||
val illuminator = withArgCaptor<Runnable> {
|
||||
verify(hbmProvider).enableHbm(anyInt(), nullable(Surface::class.java), capture())
|
||||
verify(hbmProvider).enableHbm(capture())
|
||||
}
|
||||
|
||||
assertThat(view.isIlluminationRequested).isTrue()
|
||||
|
||||
@@ -2098,7 +2098,6 @@ public class DisplayModeDirector {
|
||||
|
||||
private class UdfpsObserver extends IUdfpsHbmListener.Stub {
|
||||
private final SparseBooleanArray mLocalHbmEnabled = new SparseBooleanArray();
|
||||
private final SparseBooleanArray mGlobalHbmEnabled = new SparseBooleanArray();
|
||||
|
||||
public void observe() {
|
||||
StatusBarManagerInternal statusBar =
|
||||
@@ -2109,39 +2108,27 @@ public class DisplayModeDirector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHbmEnabled(int hbmType, int displayId) {
|
||||
public void onHbmEnabled(int displayId) {
|
||||
synchronized (mLock) {
|
||||
updateHbmStateLocked(hbmType, displayId, true /*enabled*/);
|
||||
updateHbmStateLocked(displayId, true /*enabled*/);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHbmDisabled(int hbmType, int displayId) {
|
||||
public void onHbmDisabled(int displayId) {
|
||||
synchronized (mLock) {
|
||||
updateHbmStateLocked(hbmType, displayId, false /*enabled*/);
|
||||
updateHbmStateLocked(displayId, false /*enabled*/);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHbmStateLocked(int hbmType, int displayId, boolean enabled) {
|
||||
switch (hbmType) {
|
||||
case UdfpsObserver.LOCAL_HBM:
|
||||
mLocalHbmEnabled.put(displayId, enabled);
|
||||
break;
|
||||
case UdfpsObserver.GLOBAL_HBM:
|
||||
mGlobalHbmEnabled.put(displayId, enabled);
|
||||
break;
|
||||
default:
|
||||
Slog.w(TAG, "Unknown HBM type reported. Ignoring.");
|
||||
return;
|
||||
}
|
||||
private void updateHbmStateLocked(int displayId, boolean enabled) {
|
||||
mLocalHbmEnabled.put(displayId, enabled);
|
||||
updateVoteLocked(displayId);
|
||||
}
|
||||
|
||||
private void updateVoteLocked(int displayId) {
|
||||
final Vote vote;
|
||||
if (mGlobalHbmEnabled.get(displayId)) {
|
||||
vote = Vote.forRefreshRates(60f, 60f);
|
||||
} else if (mLocalHbmEnabled.get(displayId)) {
|
||||
if (mLocalHbmEnabled.get(displayId)) {
|
||||
Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
|
||||
float maxRefreshRate = 0f;
|
||||
for (Display.Mode mode : modes) {
|
||||
@@ -2165,13 +2152,6 @@ public class DisplayModeDirector {
|
||||
final String enabled = mLocalHbmEnabled.valueAt(i) ? "enabled" : "disabled";
|
||||
pw.println(" Display " + displayId + ": " + enabled);
|
||||
}
|
||||
pw.println(" mGlobalHbmEnabled: ");
|
||||
for (int i = 0; i < mGlobalHbmEnabled.size(); i++) {
|
||||
final int displayId = mGlobalHbmEnabled.keyAt(i);
|
||||
final String enabled = mGlobalHbmEnabled.valueAt(i) ? "enabled" : "disabled";
|
||||
pw.println(" Display " + displayId + ": " + enabled);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REF
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
|
||||
|
||||
@@ -919,16 +919,6 @@ public class DisplayModeDirectorTest {
|
||||
// Should be no vote initially
|
||||
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_UDFPS);
|
||||
assertNull(vote);
|
||||
|
||||
// Enabling GHBM votes for 60hz
|
||||
hbmListener.onHbmEnabled(IUdfpsHbmListener.GLOBAL_HBM, DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_UDFPS);
|
||||
assertVoteForRefreshRate(vote, 60.f);
|
||||
|
||||
// Disabling GHBM removes the vote
|
||||
hbmListener.onHbmDisabled(IUdfpsHbmListener.GLOBAL_HBM, DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_UDFPS);
|
||||
assertNull(vote);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user