Add PropertyUtils to get first_api_level property

Also add host-side PropertyUtil class for easy retrieval of first_api_level
property

bug: 34680303
Test: make cts, run unit tests
merged-in: I97257ae109a37e54a8a208ad4396122e5ce1251e
Change-Id: I94332247c3b8eac0e5959cbc72be1062d7582d8e
diff --git a/common/device-side/util/Android.mk b/common/device-side/util/Android.mk
index 350c2db..8eb125c 100644
--- a/common/device-side/util/Android.mk
+++ b/common/device-side/util/Android.mk
@@ -24,7 +24,8 @@
 
 LOCAL_MODULE := compatibility-device-util
 
-LOCAL_SDK_VERSION := current
+# uncomment when b/13282254 is fixed
+#LOCAL_SDK_VERSION := current
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/PropertyUtil.java b/common/device-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
new file mode 100644
index 0000000..1a1ec19
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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 android.os.Build;
+import android.os.SystemProperties;
+
+/**
+ * Device-side utility class for reading properties and gathering information for testing
+ * Android device compatibility.
+ */
+public class PropertyUtil {
+
+    /**
+     * Name of read-only property detailing the first API level for which the product was
+     * shipped. Property should be undefined for factory ROM products.
+     */
+    public static String FIRST_API_LEVEL = "ro.product.first_api_level";
+
+    /** Value to be returned by getPropertyInt() if property is not found */
+    public static int INT_VALUE_IF_UNSET = -1;
+
+    /** Returns whether the device build is the factory ROM */
+    public static boolean isFactoryROM() {
+        // property should be undefined if and only if the product is factory ROM.
+        return getPropertyInt(FIRST_API_LEVEL) == INT_VALUE_IF_UNSET;
+    }
+
+    /**
+     * 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() {
+        int firstApiLevel = getPropertyInt(FIRST_API_LEVEL);
+        return (firstApiLevel == INT_VALUE_IF_UNSET) ? Build.VERSION.SDK_INT : firstApiLevel;
+    }
+
+    /**
+     * Retrieves the desired integer property, returning INT_VALUE_IF_UNSET if not found.
+     */
+    public static int getPropertyInt(String property) {
+        return SystemProperties.getInt(property, INT_VALUE_IF_UNSET);
+    }
+}
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
new file mode 100644
index 0000000..199b826
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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 com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+
+/**
+ * Host-side utility class for reading properties and gathering information for testing
+ * Android device compatibility.
+ */
+public class PropertyUtil {
+
+    /**
+     * Name of read-only property detailing the first API level for which the product was
+     * shipped. Property should be undefined for factory ROM products.
+     */
+    public static String FIRST_API_LEVEL = "ro.product.first_api_level";
+
+    /** Returns whether the device build is the factory ROM */
+    public static boolean isFactoryROM(ITestDevice device) throws DeviceNotAvailableException {
+        // first API level property should be undefined if and only if the product is factory ROM.
+        return device.getProperty(FIRST_API_LEVEL) == null;
+    }
+
+    /**
+     * 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);
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/EncryptionTest.java b/tests/tests/security/src/android/security/cts/EncryptionTest.java
index 1d37ec6..85d82e2 100644
--- a/tests/tests/security/src/android/security/cts/EncryptionTest.java
+++ b/tests/tests/security/src/android/security/cts/EncryptionTest.java
@@ -16,12 +16,13 @@
 
 package android.security.cts;
 
+import com.android.compatibility.common.util.PropertyUtil;
+
 import android.test.AndroidTestCase;
 import junit.framework.TestCase;
 
 import android.app.ActivityManager;
 import android.content.Context;
-import android.os.SystemProperties;
 import android.util.Log;
 import java.io.BufferedReader;
 import java.io.FileReader;
@@ -34,7 +35,7 @@
         System.loadLibrary("ctssecurity_jni");
     }
 
-    private static final int min_api_level = 23;
+    private static final int MIN_API_LEVEL = 23;
 
     private static final String TAG = "EncryptionTest";
 
@@ -77,15 +78,8 @@
     }
 
     private boolean isRequired() {
-        int first_api_level =
-            SystemProperties.getInt("ro.product.first_api_level", 0);
-
-        // Optional before min_api_level or if the device has low RAM
-        if (first_api_level > 0 && first_api_level < min_api_level) {
-            return false;
-        } else {
-            return !hasLowRAM();
-        }
+        // Optional before MIN_API_LEVEL or if the device has low RAM
+        return PropertyUtil.getFirstApiLevel() >= MIN_API_LEVEL && !hasLowRAM();
     }
 
     public void testConfig() throws Exception {