Update low ram device test for new memory requirements

bug:20222250
Change-Id: Id71847b222b2ec913c148bd88ccf308212fdf1e2
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
index 7c711a2..0e09e8c 100644
--- a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
@@ -16,9 +16,28 @@
 
 package android.hardware.cts;
 
+import static android.content.res.Configuration.SCREENLAYOUT_SIZE_LARGE;
+import static android.content.res.Configuration.SCREENLAYOUT_SIZE_NORMAL;
+import static android.content.res.Configuration.SCREENLAYOUT_SIZE_SMALL;
+import static android.content.res.Configuration.SCREENLAYOUT_SIZE_XLARGE;
+
+import static android.util.DisplayMetrics.DENSITY_400;
+import static android.util.DisplayMetrics.DENSITY_560;
+import static android.util.DisplayMetrics.DENSITY_HIGH;
+import static android.util.DisplayMetrics.DENSITY_LOW;
+import static android.util.DisplayMetrics.DENSITY_MEDIUM;
+import static android.util.DisplayMetrics.DENSITY_TV;
+import static android.util.DisplayMetrics.DENSITY_XHIGH;
+
 import android.app.ActivityManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.os.Build;
 import android.test.AndroidTestCase;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+import android.util.Log;
 
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -31,45 +50,142 @@
  */
 public class LowRamDeviceTest extends AndroidTestCase {
 
-    private static final int LOW_RAM_DEVICE_MEMORY_THRESHOLD_KB = 512 * 1024;
+    private static final long ONE_MEGABYTE = 1048576L;
+    private static final String TAG = "LowRamDeviceTest";
 
-    public void testLowRamProductProperty() throws Exception {
-        ActivityManager am =
+    private PackageManager mPackageManager;
+    private ActivityManager mActivityManager;
+    private DisplayMetrics mDisplayMetrics;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mPackageManager = getContext().getPackageManager();
+        mActivityManager =
                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
 
-        if (totalAvailableSystemMemory() <= LOW_RAM_DEVICE_MEMORY_THRESHOLD_KB) {
-            assertTrue("Device must specify low RAM property: ro.config.low_ram=true",
-                    am.isLowRamDevice());
+        mDisplayMetrics = new DisplayMetrics();
+        WindowManager windowManager =
+                (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+        windowManager.getDefaultDisplay().getMetrics(mDisplayMetrics);
+    }
+
+    /**
+     * Test the devices reported memory to ensure it meets the minimum values described
+     * in CDD 7.6.1.
+     */
+    public void testMinimumMemory() {
+        int density = mDisplayMetrics.densityDpi;
+        Boolean supports64Bit = supportsSixtyFourBit();
+        int screenSize = getScreenSize();
+        Boolean lowRamDevice = mActivityManager.isLowRamDevice();
+        Boolean watch = mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
+
+        Log.i(TAG, String.format("density=%d, supports64Bit=%s, screenSize=%d, watch=%s",
+                density, supports64Bit, screenSize, watch));
+
+        if (watch) {
+            assertFalse("Device is not expected to be 64-bit", supports64Bit);
+            assertMinMemoryMb(416);
+        } else if (lessThanDpi(density, DENSITY_HIGH, screenSize,
+                SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
+                lessThanDpi(density, DENSITY_MEDIUM, screenSize, SCREENLAYOUT_SIZE_LARGE) ||
+                lessThanDpi(density, DENSITY_LOW, screenSize, SCREENLAYOUT_SIZE_XLARGE)) {
+
+            assertFalse("Device is not expected to be 64-bit", supports64Bit);
+            assertMinMemoryMb(424);
+        } else if (greaterThanDpi(density, DENSITY_XHIGH, screenSize,
+                SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
+                greaterThanDpi(density, DENSITY_TV, screenSize, SCREENLAYOUT_SIZE_LARGE) ||
+                greaterThanDpi(density, DENSITY_MEDIUM, screenSize, SCREENLAYOUT_SIZE_XLARGE)) {
+
+            if (supports64Bit) {
+                assertMinMemoryMb(832);
+            } else {
+                assertMinMemoryMb(512);
+            }
+        } else if (greaterThanDpi(density, DENSITY_400, screenSize,
+                SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
+                greaterThanDpi(density, DENSITY_XHIGH, screenSize, SCREENLAYOUT_SIZE_LARGE) ||
+                greaterThanDpi(density, DENSITY_TV, screenSize, SCREENLAYOUT_SIZE_XLARGE)) {
+
+            if (supports64Bit) {
+                assertMinMemoryMb(1280);
+            } else {
+                assertMinMemoryMb(896);
+            }
+        } else if (greaterThanDpi(density, DENSITY_560, screenSize,
+                SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
+                greaterThanDpi(density, DENSITY_400, screenSize, SCREENLAYOUT_SIZE_LARGE) ||
+                greaterThanDpi(density, DENSITY_XHIGH, screenSize, SCREENLAYOUT_SIZE_XLARGE)) {
+
+            if (supports64Bit) {
+                assertMinMemoryMb(1824);
+            } else {
+                assertMinMemoryMb(1344);
+            }
         }
     }
 
     /**
-     * Returns the total amount of memory in kilobytes available to the system.
+     * @return the total memory accessible by the kernel as defined by
+     * {@code ActivityManager.MemoryInfo}.
      */
-    private int totalAvailableSystemMemory() throws IOException {
-        final String property = "MemTotal";
-        InputStream is = new FileInputStream("/proc/meminfo");
-        try {
-            Scanner scanner = new Scanner(is);
-            while (scanner.hasNextLine()) {
-                String line = scanner.nextLine();
-                if (line.startsWith(property)) {
-                    StringTokenizer tokenizer = new StringTokenizer(line);
-                    if (tokenizer.countTokens() != 3) {
-                        throw new IOException("Malformed " + property + " line");
-                    }
-
-                    // Skips over "MemTotal:"
-                    tokenizer.nextToken();
-
-                    return Integer.parseInt(tokenizer.nextToken());
-                }
-            }
-            throw new IOException(property + " could not be found");
-
-        } finally {
-            is.close();
-        }
+    private long getTotalMemory() {
+        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
+        mActivityManager.getMemoryInfo(memoryInfo);
+        return memoryInfo.totalMem;
     }
 
+    /** @return the screen size as defined in {@Configuration}. */
+    private int getScreenSize() {
+        Configuration config = getContext().getResources().getConfiguration();
+        return config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
+    }
+
+    /** @return true iff this device supports 64 bit ABIs */
+    private static boolean supportsSixtyFourBit() {
+        return Build.SUPPORTED_64_BIT_ABIS.length > 0;
+    }
+
+    /** Asserts that the given values conform to the specs in CDD 7.6.1 */
+    private void assertMinMemoryMb(long minMb) {
+
+        long totalMemoryMb = getTotalMemory() / ONE_MEGABYTE;
+        boolean lowRam = totalMemoryMb <= minMb * 1.5;
+        boolean lowRamDevice = mActivityManager.isLowRamDevice();
+
+        Log.i(TAG, String.format("minMb=%,d", minMb));
+        Log.i(TAG, String.format("totalMemoryMb=%,d", totalMemoryMb));
+        Log.i(TAG, "lowRam=" + lowRam);
+        Log.i(TAG, "lowRamDevice=" + lowRamDevice);
+
+        assertTrue(String.format("Does not meet minimum memory requirements (CDD 7.6.1)."
+                + "Found = %d, Minimum = %d", totalMemoryMb, minMb), totalMemoryMb >= minMb);
+
+        assertTrue("Device must specify low RAM property: ro.config.low_ram=true",
+                !lowRam || (lowRam && lowRamDevice));
+    }
+
+    private static boolean lessThanDpi(int actualDensityDpi, int expectedDensityDpi,
+            int actualScreenSize, int... expectedScreenSizes) {
+        return actualDensityDpi <= expectedDensityDpi &&
+                contains(expectedScreenSizes, actualScreenSize);
+    }
+
+    private static boolean greaterThanDpi(int actualDensityDpi, int expectedDensityDpi,
+            int actualScreenSize, int... expectedScreenSizes) {
+        return actualDensityDpi >= expectedDensityDpi &&
+                contains(expectedScreenSizes, actualScreenSize);
+    }
+
+    /** @return true iff the {@code array} contains the {@code target} */
+    private static boolean contains(int [] array, int target) {
+        for(int a : array) {
+            if (a == target) {
+                return true;
+            }
+        }
+        return false;
+    }
 }