CTS tests for android.view.Display

Create an overlay display on the device whose parameters
we control. Test the Display API against this overlay display.

Also remove Display test from tests/tests/view.

Bug 7067202 fixed.

Change-Id: I724e80b8a70aca46d8a7ab1c6dea050b3fe6a02b
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 4af2ac8..05da213 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -62,6 +62,7 @@
 	CtsCalendarcommon2TestCases \
 	CtsContentTestCases \
 	CtsDatabaseTestCases \
+	CtsDisplayTestCases \
 	CtsDpiTestCases \
 	CtsDpiTestCases2 \
 	CtsDrmTestCases \
diff --git a/tests/tests/display/Android.mk b/tests/tests/display/Android.mk
new file mode 100644
index 0000000..ec5b40d
--- /dev/null
+++ b/tests/tests/display/Android.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsDisplayTestCases
+
+LOCAL_SDK_VERSION := current
+
+# This test runner sets up/cleans up the device before/after running the tests.
+LOCAL_CTS_TEST_RUNNER := com.android.cts.tradefed.testtype.DisplayTestRunner
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/display/AndroidManifest.xml b/tests/tests/display/AndroidManifest.xml
new file mode 100644
index 0000000..1ddce5a
--- /dev/null
+++ b/tests/tests/display/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.display">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+                     android:targetPackage="com.android.cts.display"
+                     android:label="CTS tests of android.view.display"/>
+
+</manifest>
+
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
new file mode 100644
index 0000000..595f7148
--- /dev/null
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2012 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 android.display.cts;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.hardware.display.DisplayManager;
+import android.test.AndroidTestCase;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+
+public class DisplayTest extends AndroidTestCase {
+    // This test is called from DisplayTestRunner which brings up an overlay display on the target
+    // device. The overlay display parameters must match the ones defined there which are
+    // 1281x721/214 (wxh/dpi).
+
+    private static final int SECONDARY_DISPLAY_WIDTH = 1281;
+    private static final int SECONDARY_DISPLAY_HEIGHT = 721;
+    private static final int SECONDARY_DISPLAY_DPI = 214;
+    private static final float SCALE_DENSITY_LOWER_BOUND =
+            (float)(SECONDARY_DISPLAY_DPI - 1) / DisplayMetrics.DENSITY_DEFAULT;
+    private static final float SCALE_DENSITY_UPPER_BOUND =
+            (float)(SECONDARY_DISPLAY_DPI + 1) / DisplayMetrics.DENSITY_DEFAULT;
+    // Matches com.android.internal.R.string.display_manager_overlay_display_name.
+    private static final String OVERLAY_DISPLAY_NAME_PREFIX = "Overlay #";
+
+    private DisplayManager mDisplayManager;
+    private WindowManager mWindowManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDisplayManager = (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
+        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+    }
+
+    private boolean isSecondarySize(Display display) {
+        final Point p = new Point();
+        display.getSize(p);
+        return p.x == SECONDARY_DISPLAY_WIDTH && p.y == SECONDARY_DISPLAY_HEIGHT;
+    }
+
+    private Display getSecondaryDisplay(Display[] displays) {
+        for (Display display : displays) {
+            if (isSecondarySize(display)) {
+                return display;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Verify that the getDisplays method returns both a default and an overlay display.
+     */
+    public void testGetDisplays() {
+        Display[] displays = mDisplayManager.getDisplays();
+        assertNotNull(displays);
+        assertTrue(2 <= displays.length);
+        boolean hasDefaultDisplay = false;
+        boolean hasSecondaryDisplay = false;
+        for (Display display : displays) {
+            if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+                hasDefaultDisplay = true;
+            }
+            if (isSecondarySize(display)) {
+                hasSecondaryDisplay = true;
+            }
+        }
+        assertTrue(hasDefaultDisplay);
+        assertTrue(hasSecondaryDisplay);
+    }
+
+    /**
+     * Verify that the WindowManager returns the default display.
+     */
+    public void testDefaultDisplay() {
+        assertEquals(Display.DEFAULT_DISPLAY, mWindowManager.getDefaultDisplay().getDisplayId());
+    }
+
+    /**
+     * Verify that there is a secondary display.
+     */
+    public void testSecondaryDisplay() {
+        Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
+        assertNotNull(display);
+        assertTrue(Display.DEFAULT_DISPLAY != display.getDisplayId());
+    }
+
+    /**
+     * Test the properties of the secondary Display.
+     */
+    public void testGetDisplayAttrs() {
+        Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
+
+        assertEquals(SECONDARY_DISPLAY_WIDTH, display.getWidth());
+        assertEquals(SECONDARY_DISPLAY_HEIGHT, display.getHeight());
+
+        Point outSize = new Point();
+        display.getSize(outSize);
+        assertEquals(SECONDARY_DISPLAY_WIDTH, outSize.x);
+        assertEquals(SECONDARY_DISPLAY_HEIGHT, outSize.y);
+
+        assertEquals(0, display.getOrientation());
+
+        assertEquals(PixelFormat.RGBA_8888, display.getPixelFormat());
+
+        assertTrue(0 < display.getRefreshRate());
+
+        assertTrue(display.getName().contains(OVERLAY_DISPLAY_NAME_PREFIX));
+    }
+
+    /**
+     * Test that the getMetrics method fills in correct values.
+     */
+    public void testGetMetrics() {
+        Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
+
+        Point outSize = new Point();
+        display.getSize(outSize);
+
+        DisplayMetrics outMetrics = new DisplayMetrics();
+        outMetrics.setToDefaults();
+        display.getMetrics(outMetrics);
+
+        assertEquals(SECONDARY_DISPLAY_WIDTH, outMetrics.widthPixels);
+        assertEquals(SECONDARY_DISPLAY_HEIGHT, outMetrics.heightPixels);
+
+        // The scale is in [0.1, 3], and density is the scale factor.
+        assertTrue(SCALE_DENSITY_LOWER_BOUND <= outMetrics.density
+                && outMetrics.density <= SCALE_DENSITY_UPPER_BOUND);
+        assertTrue(SCALE_DENSITY_LOWER_BOUND <= outMetrics.scaledDensity
+                && outMetrics.scaledDensity <= SCALE_DENSITY_UPPER_BOUND);
+
+        assertEquals(SECONDARY_DISPLAY_DPI, outMetrics.densityDpi);
+        assertEquals((float)SECONDARY_DISPLAY_DPI, outMetrics.xdpi);
+        assertEquals((float)SECONDARY_DISPLAY_DPI, outMetrics.ydpi);
+    }
+
+    /**
+     * Test that the getCurrentSizeRange method returns correct values.
+     */
+    public void testGetCurrentSizeRange() {
+        Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
+
+        Point smallest = new Point();
+        Point largest = new Point();
+        display.getCurrentSizeRange(smallest, largest);
+
+        assertEquals(SECONDARY_DISPLAY_WIDTH, smallest.x);
+        assertEquals(SECONDARY_DISPLAY_HEIGHT, smallest.y);
+        assertEquals(SECONDARY_DISPLAY_WIDTH, largest.x);
+        assertEquals(SECONDARY_DISPLAY_HEIGHT, largest.y);
+    }
+
+    /**
+     * Test that the getFlags method returns no flag bits set for the overlay display.
+     */
+    public void testFlags() {
+        Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
+
+        assertEquals(0, display.getFlags());
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/DisplayTest.java b/tests/tests/view/src/android/view/cts/DisplayTest.java
deleted file mode 100644
index 489282a..0000000
--- a/tests/tests/view/src/android/view/cts/DisplayTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.view.cts;
-
-import android.content.Context;
-import android.test.AndroidTestCase;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.WindowManager;
-
-public class DisplayTest extends AndroidTestCase {
-
-    /**
-     * Test the properties of Display, they are:
-     * 1 index of this display
-     * 2 height of this display in pixels
-     * 3 width of this display in pixels
-     * 4 orientation of this display
-     * 5 pixel format of this display
-     * 6 refresh rate of this display in frames per second
-     * 7 Initialize a DisplayMetrics object from this display's data
-     */
-    public void testGetDisplayAttrs() {
-        Context con = getContext();
-        WindowManager windowManager = (WindowManager) con.getSystemService(Context.WINDOW_SERVICE);
-        Display display = windowManager.getDefaultDisplay();
-
-        assertEquals(Display.DEFAULT_DISPLAY, display.getDisplayId());
-        assertTrue(0 < display.getHeight());
-        assertTrue(0 < display.getWidth());
-        display.getOrientation();
-        assertTrue(0 < display.getPixelFormat());
-        assertTrue(0 < display.getRefreshRate());
-
-        DisplayMetrics outMetrics = new DisplayMetrics();
-        outMetrics.setToDefaults();
-        display.getMetrics(outMetrics);
-        assertEquals(display.getHeight(), outMetrics.heightPixels);
-        assertEquals(display.getWidth(), outMetrics.widthPixels);
-
-        // The scale is in [0.1, 3], and density is the scale factor.
-        assertTrue(0.1f <= outMetrics.density && outMetrics.density <= 3.0f);
-        assertTrue(0.1f <= outMetrics.scaledDensity && outMetrics.density <= 3.0f);
-        assertTrue(0 < outMetrics.xdpi);
-        assertTrue(0 < outMetrics.ydpi);
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/SettingsToggler.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/SettingsToggler.java
index 69d4c8a..ff6c4f4 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/SettingsToggler.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/SettingsToggler.java
@@ -22,52 +22,98 @@
  * {@link SettingsToggler} sets settings by using the "adb shell content" command.
  */
 public class SettingsToggler {
+    private static final String GROUP_SECURE = "secure";
+    private static final String GROUP_GLOBAL = "global";
+
+    /** Sets a setting by deleting and then inserting the string value. */
+    public static void setString(ITestDevice device, String group, String name, String value)
+            throws DeviceNotAvailableException {
+        deleteSetting(device, group, name);
+        device.executeShellCommand(
+                "content insert"
+                + " --uri content://settings/" + group
+                + " --bind name:s:" + name
+                + " --bind value:s:" + value);
+    }
 
     /** Sets a secure setting by deleting and then inserting the string value. */
     public static void setSecureString(ITestDevice device, String name, String value)
             throws DeviceNotAvailableException {
-        deleteSecure(device, name);
+        setString(device, GROUP_SECURE, name, value);
+    }
+
+    /** Sets a global setting by deleting and then inserting the string value. */
+    public static void setGlobalString(ITestDevice device, String name, String value)
+            throws DeviceNotAvailableException {
+        setString(device, GROUP_GLOBAL, name, value);
+    }
+
+    /** Sets a setting by deleting and then inserting the int value. */
+    public static void setInt(ITestDevice device, String group, String name, int value)
+            throws DeviceNotAvailableException {
+        deleteSetting(device, group, name);
         device.executeShellCommand(
                 "content insert"
-                + " --uri content://settings/secure"
+                + " --uri content://settings/" + group
                 + " --bind name:s:" + name
-                + " --bind value:s:" + value);
+                + " --bind value:i:" + value);
     }
 
     /** Sets a secure setting by deleting and then inserting the int value. */
     public static void setSecureInt(ITestDevice device, String name, int value)
             throws DeviceNotAvailableException {
-        deleteSecure(device, name);
+        setInt(device, GROUP_SECURE, name, value);
+    }
+
+    /** Sets a global setting by deleting and then inserting the int value. */
+    public static void setGlobalInt(ITestDevice device, String name, int value)
+            throws DeviceNotAvailableException {
+        setInt(device, GROUP_GLOBAL, name, value);
+    }
+
+    public static void updateString(ITestDevice device, String group, String name, String value)
+            throws DeviceNotAvailableException {
         device.executeShellCommand(
-                "content insert"
-                + " --uri content://settings/secure"
-                + " --bind name:s:" + name
-                + " --bind value:i:" + value);
+                "content update"
+                + " --uri content://settings/" + group
+                + " --bind value:s:" + value
+                + " --where \"name='" + name + "'\"");
     }
 
     public static void updateSecureString(ITestDevice device, String name, String value)
             throws DeviceNotAvailableException {
+        updateString(device, GROUP_SECURE, name, value);
+    }
+
+    public static void updateGlobalString(ITestDevice device, String name, String value)
+            throws DeviceNotAvailableException {
+        updateString(device, GROUP_GLOBAL, name, value);
+    }
+
+    public static void updateInt(ITestDevice device, String group, String name, int value)
+            throws DeviceNotAvailableException {
         device.executeShellCommand(
                 "content update"
-                + " --uri content://settings/secure"
-                + " --bind value:s:" + value
+                + " --uri content://settings/" + group
+                + " --bind value:i:" + value
                 + " --where \"name='" + name + "'\"");
     }
 
     public static void updateSecureInt(ITestDevice device, String name, int value)
             throws DeviceNotAvailableException {
-        device.executeShellCommand(
-                "content update"
-                + " --uri content://settings/secure"
-                + " --bind value:i:" + value
-                + " --where \"name='" + name + "'\"");
+        updateInt(device, GROUP_SECURE, name, value);
     }
 
-    private static void deleteSecure(ITestDevice device, String name)
+    public static void updateGlobalInt(ITestDevice device, String name, int value)
+            throws DeviceNotAvailableException {
+        updateInt(device, GROUP_GLOBAL, name, value);
+    }
+
+    private static void deleteSetting(ITestDevice device, String group, String name)
             throws DeviceNotAvailableException {
         device.executeShellCommand(
                 "content delete"
-                + " --uri content://settings/secure"
+                + " --uri content://settings/" + group
                 + " --where \"name='" + name + "'\"");
     }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DisplayTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DisplayTestRunner.java
new file mode 100644
index 0000000..4c83aa9
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DisplayTestRunner.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 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.cts.tradefed.testtype;
+
+import com.android.cts.tradefed.targetprep.SettingsToggler;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.ITestInvocationListener;
+
+/**
+ * Running the display tests requires modification of secure settings to create an overlay display.
+ * Secure settings cannot be changed from device CTS tests since system signature permission is
+ * required. Such settings can be modified by the shell user, so a host side test is used.
+ */
+public class DisplayTestRunner extends InstrumentationApkTest {
+    private static final String OVERLAY_DISPLAY_DEVICES_SETTING_NAME = "overlay_display_devices";
+
+    // Use a non-standard pattern, must match values in tests/tests/display/.../DisplayTest.java
+    private static final String OVERLAY_DISPLAY_DEVICES_SETTING_VALUE = "1281x721/214";
+
+    @Override
+    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+        // CLog.e("run: About to enable overlay display.");
+        SettingsToggler.setGlobalString(getDevice(), OVERLAY_DISPLAY_DEVICES_SETTING_NAME,
+                OVERLAY_DISPLAY_DEVICES_SETTING_VALUE);
+
+        super.run(listener);
+
+        // Tear down overlay display.
+        // CLog.e("run: About to disable overlay display.");
+        SettingsToggler.setGlobalString(getDevice(), OVERLAY_DISPLAY_DEVICES_SETTING_NAME,
+                "");
+    }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index 0112071..9dab1a3 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -49,6 +49,8 @@
         "com.android.cts.tradefed.testtype.AccessibilityTestRunner";
     public static final String ACCESSIBILITYSERVICE_TEST =
         "com.android.cts.tradefed.testtype.AccessibilityServiceTestRunner";
+    public static final String DISPLAY_TEST =
+            "com.android.cts.tradefed.testtype.DisplayTestRunner";
 
     private static final String SIGNATURE_TEST_METHOD = "testSignature";
     private static final String SIGNATURE_TEST_CLASS = "android.tests.sigtest.SimpleSignatureTest";
@@ -229,6 +231,9 @@
         } else if (ACCESSIBILITYSERVICE_TEST.equals(mTestType)) {
             AccessibilityServiceTestRunner test = new AccessibilityServiceTestRunner();
             return setInstrumentationTest(test, testCaseDir);
+        } else if (DISPLAY_TEST.equals(mTestType)) {
+            DisplayTestRunner test = new DisplayTestRunner();
+            return setInstrumentationTest(test, testCaseDir);
         } else if (mIsSignatureTest) {
             // TODO: hardcode the runner/class/method for now, since current package xml points to
             // specialized instrumentation. Eventually this special case for signatureTest can be