blob: 5a3ea35b1194f37b2c0f3d81ffaa210891bb60ca [file] [log] [blame]
/*
* 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 android.view;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.util.DisplayMetrics;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.quality.Strictness;
import java.util.function.Consumer;
/**
* Tests for {@link Display}.
*
* <p>Build/Install/Run:
*
* atest FrameworksMockingCoreTests:android.view.DisplayTests
*/
@RunWith(AndroidJUnit4.class)
public class DisplayTests {
private static final int APP_WIDTH = 272;
private static final int APP_HEIGHT = 700;
// Tablet size device, ROTATION_0 corresponds to portrait.
private static final int LOGICAL_WIDTH = 700;
private static final int LOGICAL_HEIGHT = 1800;
// Bounds of the app when the device is in portrait mode.
private static Rect sAppBoundsPortrait = buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT);
private static Rect sAppBoundsLandscape = buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH);
private StaticMockitoSession mMockitoSession;
private DisplayManagerGlobal mDisplayManagerGlobal;
private Context mApplicationContext;
private DisplayInfo mDisplayInfo = new DisplayInfo();
@Before
public void setupTests() {
mMockitoSession = mockitoSession()
.mockStatic(DisplayManagerGlobal.class)
.strictness(Strictness.LENIENT)
.startMocking();
// Ensure no adjustments are set before each test.
mApplicationContext = ApplicationProvider.getApplicationContext();
DisplayAdjustments displayAdjustments =
mApplicationContext.getResources().getDisplayAdjustments();
displayAdjustments.setFixedRotationAdjustments(null);
mApplicationContext.getResources().overrideDisplayAdjustments(null);
mApplicationContext.getResources().getConfiguration().windowConfiguration.setAppBounds(
null);
mApplicationContext.getResources().getConfiguration().windowConfiguration.setMaxBounds(
null);
mDisplayInfo.rotation = ROTATION_0;
mDisplayManagerGlobal = mock(DisplayManagerGlobal.class);
doReturn(mDisplayInfo).when(mDisplayManagerGlobal).getDisplayInfo(anyInt());
}
@After
public void teardownTests() {
if (mMockitoSession != null) {
mMockitoSession.finishMocking();
}
Mockito.framework().clearInlineMocks();
}
@Test
public void testConstructor_defaultDisplayAdjustments_matchesDisplayInfo() {
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
assertThat(display.getDisplayAdjustments()).isEqualTo(
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
DisplayInfo actualDisplayInfo = new DisplayInfo();
display.getDisplayInfo(actualDisplayInfo);
verifyDisplayInfo(actualDisplayInfo, mDisplayInfo);
}
@Test
public void testConstructor_defaultResources_matchesDisplayInfo() {
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
assertThat(display.getDisplayAdjustments()).isEqualTo(
mApplicationContext.getResources().getDisplayAdjustments());
DisplayInfo actualDisplayInfo = new DisplayInfo();
display.getDisplayInfo(actualDisplayInfo);
verifyDisplayInfo(actualDisplayInfo, mDisplayInfo);
}
@Test
public void testGetRotation_defaultDisplayAdjustments_rotationNotAdjusted() {
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
assertThat(display.getRotation()).isEqualTo(ROTATION_0);
}
@Test
public void testGetRotation_displayAdjustmentsWithoutOverride_rotationNotAdjusted() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, but no override is set.
DisplayAdjustments displayAdjustments = DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
final FixedRotationAdjustments fixedRotationAdjustments =
new FixedRotationAdjustments(ROTATION_90, APP_WIDTH, APP_HEIGHT,
DisplayCutout.NO_CUTOUT);
displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
// GIVEN display is constructed with display adjustments.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
displayAdjustments);
// THEN rotation is not adjusted since no override was set.
assertThat(display.getRotation()).isEqualTo(ROTATION_0);
}
@Test
public void testGetRotation_resourcesWithoutOverride_rotationNotAdjusted() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, but no override is set.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN rotation is not adjusted since no override is set.
assertThat(display.getRotation()).isEqualTo(ROTATION_0);
}
@Test
public void testGetRotation_resourcesWithOverrideDisplayAdjustments_rotationAdjusted() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, and an override is set.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN rotation is adjusted since an override is set.
assertThat(display.getRotation()).isEqualTo(ROTATION_90);
}
@Test
public void testGetRealSize_defaultResourcesPortrait_matchesLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches display orientation.
verifyRealSizeIsPortrait(display);
}
@Test
public void testGetRealSize_defaultResourcesLandscape_matchesRotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches display orientation.
verifyRealSizeIsLandscape(display);
}
@Test
public void testGetRealSize_defaultDisplayAdjustmentsPortrait_matchesLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
// THEN real size matches display orientation.
verifyRealSizeIsPortrait(display);
}
@Test
public void testGetRealSize_defaultDisplayAdjustmentsLandscape_matchesLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
// THEN real size matches display orientation.
verifyRealSizeIsLandscape(display);
}
@Test
public void testGetRealSize_resourcesPortraitWithFixedRotation_notRotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches display orientation.
verifyRealSizeIsLandscape(display);
}
@Test
public void testGetRealSize_resourcesWithLandscapeFixedRotation_notRotatedLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches display orientation.
verifyRealSizeIsPortrait(display);
}
@Test
public void testGetRealSize_resourcesWithPortraitOverrideRotation_rotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, and an override is set.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app orientation.
verifyRealSizeIsPortrait(display);
}
@Test
public void testGetRealSize_resourcesWithLandscapeOverrideRotation_rotatedLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, and an override is set.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app orientation.
verifyRealSizeIsLandscape(display);
}
@Test
public void testGetRealSize_resourcesPortraitSandboxed_matchesSandboxBounds() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN app is letterboxed.
setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
sAppBoundsPortrait);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app bounds.
verifyRealSizeMatchesApp(display, sAppBoundsPortrait);
}
@Test
public void testGetRealSize_resourcesLandscapeSandboxed_matchesSandboxBounds() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN app is letterboxed.
setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
sAppBoundsLandscape);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app bounds.
verifyRealSizeMatchesApp(display, sAppBoundsLandscape);
}
@Test
public void testGetRealMetrics_defaultResourcesPortrait_matchesLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches display orientation.
verifyRealMetricsIsPortrait(display);
}
@Test
public void testGetRealMetrics_defaultResourcesLandscape_matchesRotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches display orientation.
verifyRealMetricsIsLandscape(display);
}
@Test
public void testGetRealMetrics_defaultDisplayAdjustmentsPortrait_matchesLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
// THEN real metrics matches display orientation.
verifyRealMetricsIsPortrait(display);
}
@Test
public void testGetRealMetrics_defaultDisplayAdjustmentsLandscape_matchesLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
// THEN real metrics matches display orientation.
verifyRealMetricsIsLandscape(display);
}
@Test
public void testGetRealMetrics_resourcesPortraitWithFixedRotation_notRotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches display orientation.
verifyRealMetricsIsLandscape(display);
}
@Test
public void testGetRealMetrics_resourcesWithLandscapeFixedRotation_notRotatedLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches display orientation.
verifyRealMetricsIsPortrait(display);
}
@Test
public void testGetRealMetrics_resourcesWithPortraitOverrideRotation_rotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated with an override.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app orientation.
verifyRealMetricsIsPortrait(display);
}
@Test
public void testGetRealMetrics_resourcesWithLandscapeOverrideRotation_rotatedLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app orientation.
verifyRealMetricsIsLandscape(display);
}
@Test
public void testGetRealMetrics_resourcesPortraitSandboxed_matchesSandboxBounds() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN app is letterboxed.
setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
sAppBoundsPortrait);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app bounds.
verifyRealMetricsMatchesApp(display, sAppBoundsPortrait);
}
@Test
public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesSandboxBounds() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN app is letterboxed.
setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
sAppBoundsLandscape);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app bounds.
verifyRealMetricsMatchesApp(display, sAppBoundsLandscape);
}
// Given rotated display dimensions, calculate the letterboxed app bounds.
private static Rect buildAppBounds(int displayWidth, int displayHeight) {
final int midWidth = displayWidth / 2;
final int left = midWidth - (APP_WIDTH / 2);
final int right = midWidth + (APP_WIDTH / 2);
final int midHeight = displayHeight / 2;
// Coordinate system starts at top left.
final int top = midHeight - (APP_HEIGHT / 2);
final int bottom = midHeight + (APP_HEIGHT / 2);
return new Rect(left, top, right, bottom);
}
private static void setDisplayInfoLandscape(DisplayInfo displayInfo) {
displayInfo.rotation = ROTATION_90;
// Flip width & height assignment since the device is rotated.
displayInfo.logicalWidth = LOGICAL_HEIGHT;
displayInfo.logicalHeight = LOGICAL_WIDTH;
}
private static void setDisplayInfoPortrait(DisplayInfo displayInfo) {
displayInfo.rotation = ROTATION_0;
displayInfo.logicalWidth = LOGICAL_WIDTH;
displayInfo.logicalHeight = LOGICAL_HEIGHT;
}
/**
* Set max bounds to be sandboxed to the app bounds, indicating the app is in
* size compat mode or letterbox.
*/
private static void setMaxBoundsSandboxedToMatchAppBounds(Resources resources, Rect appBounds) {
resources.getConfiguration().windowConfiguration.setMaxBounds(appBounds);
}
/**
* Do not compare entire display info, since it is updated to match display the test is run on.
*/
private static void verifyDisplayInfo(DisplayInfo actual, DisplayInfo expected) {
assertThat(actual.displayId).isEqualTo(expected.displayId);
assertThat(actual.rotation).isEqualTo(expected.rotation);
assertThat(actual.logicalWidth).isEqualTo(LOGICAL_WIDTH);
assertThat(actual.logicalHeight).isEqualTo(LOGICAL_HEIGHT);
}
private static void verifyRealSizeIsLandscape(Display display) {
Point size = new Point();
display.getRealSize(size);
// Flip the width and height check since the device is rotated.
assertThat(size).isEqualTo(new Point(LOGICAL_HEIGHT, LOGICAL_WIDTH));
}
private static void verifyRealMetricsIsLandscape(Display display) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
// Flip the width and height check since the device is rotated.
assertThat(metrics.widthPixels).isEqualTo(LOGICAL_HEIGHT);
assertThat(metrics.heightPixels).isEqualTo(LOGICAL_WIDTH);
}
private static void verifyRealSizeIsPortrait(Display display) {
Point size = new Point();
display.getRealSize(size);
assertThat(size).isEqualTo(new Point(LOGICAL_WIDTH, LOGICAL_HEIGHT));
}
private static void verifyRealMetricsIsPortrait(Display display) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
assertThat(metrics.widthPixels).isEqualTo(LOGICAL_WIDTH);
assertThat(metrics.heightPixels).isEqualTo(LOGICAL_HEIGHT);
}
private static void verifyRealSizeMatchesApp(Display display, Rect appBounds) {
Point size = new Point();
display.getRealSize(size);
assertThat(size).isEqualTo(new Point(appBounds.width(), appBounds.height()));
}
private static void verifyRealMetricsMatchesApp(Display display, Rect appBounds) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
assertThat(metrics.widthPixels).isEqualTo(appBounds.width());
assertThat(metrics.heightPixels).isEqualTo(appBounds.height());
}
private static FixedRotationAdjustments setOverrideFixedRotationAdjustments(
Resources resources, @Surface.Rotation int rotation) {
FixedRotationAdjustments fixedRotationAdjustments =
setFixedRotationAdjustments(resources, rotation);
resources.overrideDisplayAdjustments(
buildOverrideRotationAdjustments(fixedRotationAdjustments));
return fixedRotationAdjustments;
}
private static FixedRotationAdjustments setFixedRotationAdjustments(Resources resources,
@Surface.Rotation int rotation) {
final FixedRotationAdjustments fixedRotationAdjustments =
new FixedRotationAdjustments(rotation, APP_WIDTH, APP_HEIGHT,
DisplayCutout.NO_CUTOUT);
resources.getDisplayAdjustments().setFixedRotationAdjustments(fixedRotationAdjustments);
return fixedRotationAdjustments;
}
private static Consumer<DisplayAdjustments> buildOverrideRotationAdjustments(
FixedRotationAdjustments fixedRotationAdjustments) {
return consumedDisplayAdjustments
-> consumedDisplayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
}
}