Define getVendorApiLevel() function

Vendor API level is defined in ro.board.api_level or
ro.board.first_api_level. Define getVendorApiLevel() to read the API
level of the vendor implementation.

Bug: 181284704
Test: atest compatibility-host-util-tests
Change-Id: I8260257705f3d55d1d5f9fd5889319a374095f93
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java b/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
index b354f66..b833a8f 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -38,11 +38,16 @@
     private static final String BUILD_TYPE_PROPERTY = "ro.build.type";
     private static final String MANUFACTURER_PROPERTY = "ro.product.manufacturer";
     private static final String TAG_DEV_KEYS = "dev-keys";
+    private static final String VENDOR_API_LEVEL = "ro.board.api_level";
+    private static final String VENDOR_FIRST_API_LEVEL = "ro.board.first_api_level";
     private static final String VNDK_VERSION = "ro.vndk.version";
 
     /** Value to be returned by getPropertyInt() if property is not found */
     public static final int INT_VALUE_IF_UNSET = -1;
 
+    /** API level for current in development */
+    public static final int API_LEVEL_CURRENT = 10000;
+
     public static final String GOOGLE_SETTINGS_QUERY =
             "content query --uri content://com.google.settings/partner";
 
@@ -63,27 +68,53 @@
     }
 
     /**
-     * Return the first API level for this product. If the read-only property is unset,
-     * this means the first API level is the current API level, and the current API level
-     * is returned.
+     * Return the first API level for this product. If the read-only property is unset, this means
+     * the first API level is the current API level, and the current API level is returned.
      */
     public static int getFirstApiLevel(ITestDevice device) throws DeviceNotAvailableException {
-        String propString = device.getProperty(FIRST_API_LEVEL);
-        return (propString == null) ? device.getApiLevel() : Integer.parseInt(propString);
+        int firstApiLevel = getPropertyInt(device, FIRST_API_LEVEL);
+        return (firstApiLevel == INT_VALUE_IF_UNSET) ? device.getApiLevel() : firstApiLevel;
     }
 
     /**
-     * Return whether the SDK version of the vendor partiton is newer than the given API level.
-     * If the property is set to non-integer value, this means the vendor partition is using
-     * current API level and true is returned.
+     * Return the API level of the vendor partition. It will read the following properties in order
+     * and returns the value of the first defined property. If none of them are defined, or the
+     * value is a VERSION CODENAME, returns the current API level which is defined in
+     * API_LEVEL_CURRENT.
+     *
+     * <ul>
+     *   <li>ro.board.api_level
+     *   <li>ro.board.first_api_level
+     *   <li>ro.vndk.version
+     * </ul>
      */
+    public static int getVendorApiLevel(ITestDevice device) throws DeviceNotAvailableException {
+        String[] vendorApiLevelProps = {
+            // Use the properties in order.
+            VENDOR_API_LEVEL, VENDOR_FIRST_API_LEVEL, VNDK_VERSION,
+        };
+        for (String prop : vendorApiLevelProps) {
+            int apiLevel = getPropertyInt(device, prop);
+            if (apiLevel != INT_VALUE_IF_UNSET) {
+                return apiLevel;
+            }
+        }
+        return API_LEVEL_CURRENT;
+    }
+
+    /** Return whether the API level of the vendor partition is newer than the given API level. */
     public static boolean isVendorApiLevelNewerThan(ITestDevice device, int apiLevel)
             throws DeviceNotAvailableException {
-        int vendorApiLevel = getPropertyInt(device, VNDK_VERSION);
-        if (vendorApiLevel == INT_VALUE_IF_UNSET) {
-            return true;
-        }
-        return vendorApiLevel > apiLevel;
+        return getVendorApiLevel(device) > apiLevel;
+    }
+
+    /**
+     * Return whether the API level of the vendor partition is same or newer than the given API
+     * level.
+     */
+    public static boolean isVendorApiLevelAtLeast(ITestDevice device, int apiLevel)
+            throws DeviceNotAvailableException {
+        return getVendorApiLevel(device) >= apiLevel;
     }
 
     /**
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/PropertyUtilTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/PropertyUtilTest.java
new file mode 100644
index 0000000..e094686
--- /dev/null
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/PropertyUtilTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.compatibility.common.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link PropertyUtil} */
+@RunWith(JUnit4.class)
+public class PropertyUtilTest {
+    private static final String FIRST_API_LEVEL = "ro.product.first_api_level";
+    private static final String VENDOR_API_LEVEL = "ro.board.api_level";
+    private static final String VENDOR_FIRST_API_LEVEL = "ro.board.first_api_level";
+    private static final String VNDK_VERSION = "ro.vndk.version";
+
+    private PropertyUtil mPropertyUtil;
+    private ITestDevice mMockDevice;
+
+    @Before
+    public void setUp() {
+        mPropertyUtil = new PropertyUtil();
+        mMockDevice = EasyMock.createMock(ITestDevice.class);
+    }
+
+    @Test
+    public void testGetFirstApiLevelFromProductFirstApiLevel() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(FIRST_API_LEVEL)).andReturn("31");
+        EasyMock.replay(mMockDevice);
+        assertEquals(31, mPropertyUtil.getFirstApiLevel(mMockDevice));
+        EasyMock.verify(mMockDevice);
+    }
+
+    @Test
+    public void testGetFirstApiLevelFromSdkVersion() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(FIRST_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getApiLevel()).andReturn(31);
+        EasyMock.replay(mMockDevice);
+        assertEquals(31, mPropertyUtil.getFirstApiLevel(mMockDevice));
+        EasyMock.verify(mMockDevice);
+    }
+
+    @Test
+    public void testGetVendorApiLevelFromVendorApiLevel() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_API_LEVEL)).andReturn("31");
+        EasyMock.replay(mMockDevice);
+        assertEquals(31, mPropertyUtil.getVendorApiLevel(mMockDevice));
+        EasyMock.verify(mMockDevice);
+    }
+
+    @Test
+    public void testGetVendorApiLevelFromVendorFirstApiLevel() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_FIRST_API_LEVEL)).andReturn("31");
+        EasyMock.replay(mMockDevice);
+        assertEquals(31, mPropertyUtil.getVendorApiLevel(mMockDevice));
+        EasyMock.verify(mMockDevice);
+    }
+
+    @Test
+    public void testGetVendorApiLevelFromVndkVersion() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_FIRST_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getProperty(VNDK_VERSION)).andReturn("31");
+        EasyMock.replay(mMockDevice);
+        assertEquals(31, mPropertyUtil.getVendorApiLevel(mMockDevice));
+        EasyMock.verify(mMockDevice);
+    }
+
+    @Test
+    public void testGetVendorApiLevelCurrent() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_FIRST_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getProperty(VNDK_VERSION)).andReturn(null);
+        EasyMock.replay(mMockDevice);
+        assertEquals(PropertyUtil.API_LEVEL_CURRENT, mPropertyUtil.getVendorApiLevel(mMockDevice));
+        EasyMock.verify(mMockDevice);
+    }
+
+    @Test
+    public void testGetVendorApiLevelCurrent2() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_FIRST_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getProperty(VNDK_VERSION)).andReturn("S");
+        EasyMock.replay(mMockDevice);
+        assertEquals(PropertyUtil.API_LEVEL_CURRENT, mPropertyUtil.getVendorApiLevel(mMockDevice));
+        EasyMock.verify(mMockDevice);
+    }
+
+    @Test
+    public void testIsVendorApiLevelNewerThan() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_API_LEVEL)).andReturn(null);
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_FIRST_API_LEVEL)).andReturn("30");
+        EasyMock.replay(mMockDevice);
+        assertFalse(mPropertyUtil.isVendorApiLevelNewerThan(mMockDevice, 30));
+        EasyMock.verify(mMockDevice);
+    }
+
+    @Test
+    public void testIsVendorApiLevelAtLeast() throws DeviceNotAvailableException {
+        EasyMock.expect(mMockDevice.getProperty(VENDOR_API_LEVEL)).andReturn("30");
+        EasyMock.replay(mMockDevice);
+        assertTrue(mPropertyUtil.isVendorApiLevelAtLeast(mMockDevice, 30));
+        EasyMock.verify(mMockDevice);
+    }
+}