blob: 48da789441e9f71d8baae1445ee10e465db13c5e [file] [log] [blame]
/*
* 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.app.Activity;
import android.app.Instrumentation;
import android.app.Presentation;
import android.app.UiAutomation;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.Presubmit;
import android.test.InstrumentationTestCase;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Display.HdrCapabilities;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class DisplayTest extends InstrumentationTestCase {
// The CTS package brings up an overlay display on the target device (see AndroidTest.xml).
// The overlay display parameters must match the ones defined there which are
// 181x161/214 (wxh/dpi). It only matters that these values are different from any real
// display.
private static final int SECONDARY_DISPLAY_WIDTH = 181;
private static final int SECONDARY_DISPLAY_HEIGHT = 161;
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;
private Context mContext;
// To test display mode switches.
private TestPresentation mPresentation;
private Activity mScreenOnActivity;
@Override
protected void setUp() throws Exception {
super.setUp();
mScreenOnActivity = launchScreenOnActivity();
mContext = getInstrumentation().getContext();
mDisplayManager = (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
@Override
protected void tearDown() throws Exception {
if (mScreenOnActivity != null) {
mScreenOnActivity.finish();
}
}
private void enableAppOps() {
StringBuilder cmd = new StringBuilder();
cmd.append("appops set ");
cmd.append(getInstrumentation().getContext().getPackageName());
cmd.append(" android:system_alert_window allow");
getInstrumentation().getUiAutomation().executeShellCommand(cmd.toString());
StringBuilder query = new StringBuilder();
query.append("appops get ");
query.append(getInstrumentation().getContext().getPackageName());
query.append(" android:system_alert_window");
String queryStr = query.toString();
String result = "No operations.";
while (result.contains("No operations")) {
ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
queryStr);
InputStream inputStream = new FileInputStream(pfd.getFileDescriptor());
result = convertStreamToString(inputStream);
}
}
private String convertStreamToString(InputStream is) {
try (java.util.Scanner s = new Scanner(is).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
}
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.
*/
@Presubmit
public void testDefaultDisplay() {
assertEquals(Display.DEFAULT_DISPLAY, mWindowManager.getDefaultDisplay().getDisplayId());
}
/**
* Verify default display's HDR capability.
*/
public void testDefaultDisplayHdrCapability() {
Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
HdrCapabilities cap = display.getHdrCapabilities();
int[] hdrTypes = cap.getSupportedHdrTypes();
for (int type : hdrTypes) {
assertTrue(type >= 1 && type <= 3);
}
assertFalse(cap.getDesiredMaxLuminance() < -1.0f);
assertFalse(cap.getDesiredMinLuminance() < -1.0f);
assertFalse(cap.getDesiredMaxAverageLuminance() < -1.0f);
}
/**
* 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(Display.FLAG_PRESENTATION, display.getFlags());
}
/**
* Tests that the mode-related attributes and methods work as expected.
*/
public void testMode() {
Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
assertEquals(2, display.getSupportedModes().length);
Display.Mode mode = display.getMode();
assertEquals(display.getSupportedModes()[0], mode);
assertEquals(SECONDARY_DISPLAY_WIDTH, mode.getPhysicalWidth());
assertEquals(SECONDARY_DISPLAY_HEIGHT, mode.getPhysicalHeight());
assertEquals(display.getRefreshRate(), mode.getRefreshRate());
}
/**
* Tests that mode switch requests are correctly executed.
*/
public void testModeSwitch() throws Exception {
enableAppOps();
final Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
Display.Mode[] modes = display.getSupportedModes();
assertEquals(2, modes.length);
Display.Mode mode = display.getMode();
assertEquals(modes[0], mode);
final Display.Mode newMode = modes[1];
Handler handler = new Handler(Looper.getMainLooper());
// Register for display events.
final CountDownLatch changeSignal = new CountDownLatch(1);
mDisplayManager.registerDisplayListener(new DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {}
@Override
public void onDisplayChanged(int displayId) {
if (displayId == display.getDisplayId()) {
changeSignal.countDown();
}
}
@Override
public void onDisplayRemoved(int displayId) {}
}, handler);
// Show the presentation.
final CountDownLatch presentationSignal = new CountDownLatch(1);
handler.post(new Runnable() {
@Override
public void run() {
mPresentation = new TestPresentation(
getInstrumentation().getContext(), display, newMode.getModeId());
mPresentation.show();
presentationSignal.countDown();
}
});
assertTrue(presentationSignal.await(5, TimeUnit.SECONDS));
// Wait until the display change is effective.
assertTrue(changeSignal.await(5, TimeUnit.SECONDS));
assertEquals(newMode, display.getMode());
handler.post(new Runnable() {
@Override
public void run() {
mPresentation.dismiss();
}
});
}
/**
* Used to force mode changes on a display.
* <p>
* Note that due to limitations of the Presentation class, the modes must have the same size
* otherwise the presentation will be automatically dismissed.
*/
private static final class TestPresentation extends Presentation {
private final int mModeId;
public TestPresentation(Context context, Display display, int modeId) {
super(context, display);
mModeId = modeId;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View content = new View(getContext());
content.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
content.setBackgroundColor(Color.RED);
setContentView(content);
WindowManager.LayoutParams params = getWindow().getAttributes();
params.preferredDisplayModeId = mModeId;
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
params.setTitle("CtsTestPresentation");
getWindow().setAttributes(params);
}
}
private Activity launchScreenOnActivity() {
Class clazz = ScreenOnActivity.class;
String targetPackage = getInstrumentation().getContext().getPackageName();
Instrumentation.ActivityResult result = new Instrumentation.ActivityResult(0, new Intent());
Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(clazz.getName(), result, false);
getInstrumentation().addMonitor(monitor);
launchActivity(targetPackage, clazz, null);
return monitor.waitForActivity();
}
}