1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package android.server.am; 18 19 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; 20 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; 21 import static android.server.am.StateLogger.logAlways; 22 import static android.support.test.InstrumentationRegistry.getContext; 23 import static android.support.test.InstrumentationRegistry.getInstrumentation; 24 25 import static org.junit.Assert.fail; 26 27 import android.graphics.PixelFormat; 28 import android.hardware.display.DisplayManager; 29 import android.hardware.display.VirtualDisplay; 30 import android.media.ImageReader; 31 import android.os.SystemClock; 32 import androidx.annotation.Nullable; 33 34 import com.android.compatibility.common.util.SystemUtil; 35 36 import java.io.IOException; 37 import java.util.Objects; 38 import java.util.function.Predicate; 39 import java.util.regex.Matcher; 40 import java.util.regex.Pattern; 41 42 /** 43 * Helper class to create virtual display. 44 */ 45 class VirtualDisplayHelper { 46 47 private static final String VIRTUAL_DISPLAY_NAME = "CtsVirtualDisplay"; 48 /** See {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD}. */ 49 private static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5; 50 51 private static final Pattern DISPLAY_DEVICE_PATTERN = Pattern.compile( 52 ".*DisplayDeviceInfo\\{\"([^\"]+)\":.*, state (\\S+),.*\\}.*"); 53 private static final int DENSITY = 160; 54 private static final int HEIGHT = 480; 55 private static final int WIDTH = 800; 56 57 private ImageReader mReader; 58 private VirtualDisplay mVirtualDisplay; 59 private boolean mCreated; 60 createAndWaitForDisplay(boolean requestShowWhenLocked)61 void createAndWaitForDisplay(boolean requestShowWhenLocked) { 62 createVirtualDisplay(requestShowWhenLocked); 63 waitForDisplayState(false /* default */, true /* on */); 64 mCreated = true; 65 } 66 turnDisplayOff()67 void turnDisplayOff() { 68 mVirtualDisplay.setSurface(null); 69 waitForDisplayState(false /* default */, false /* on */); 70 } 71 turnDisplayOn()72 void turnDisplayOn() { 73 mVirtualDisplay.setSurface(mReader.getSurface()); 74 waitForDisplayState(false /* default */, true /* on */); 75 } 76 releaseDisplay()77 void releaseDisplay() { 78 if (mCreated) { 79 mVirtualDisplay.release(); 80 mReader.close(); 81 waitForDisplayCondition(false /* defaultDisplay */, Objects::isNull, 82 "Waiting for virtual display destroy"); 83 } 84 mCreated = false; 85 } 86 createVirtualDisplay(boolean requestShowWhenLocked)87 private void createVirtualDisplay(boolean requestShowWhenLocked) { 88 mReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2); 89 90 final DisplayManager displayManager = getContext().getSystemService(DisplayManager.class); 91 92 int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; 93 if (requestShowWhenLocked) { 94 flags |= VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; 95 } 96 mVirtualDisplay = displayManager.createVirtualDisplay( 97 VIRTUAL_DISPLAY_NAME, WIDTH, HEIGHT, DENSITY, mReader.getSurface(), flags); 98 } 99 waitForDefaultDisplayState(boolean wantOn)100 static void waitForDefaultDisplayState(boolean wantOn) { 101 waitForDisplayState(true /* default */, wantOn); 102 } 103 waitForDisplayState(boolean defaultDisplay, boolean wantOn)104 private static void waitForDisplayState(boolean defaultDisplay, boolean wantOn) { 105 waitForDisplayCondition(defaultDisplay, state -> state != null && state == wantOn, 106 "Waiting for " + (defaultDisplay ? "default" : "virtual") + " display " 107 + (wantOn ? "on" : "off")); 108 } 109 waitForDisplayCondition(boolean defaultDisplay, Predicate<Boolean> condition, String message)110 private static void waitForDisplayCondition(boolean defaultDisplay, 111 Predicate<Boolean> condition, String message) { 112 for (int retry = 1; retry <= 10; retry++) { 113 if (condition.test(getDisplayState(defaultDisplay))) { 114 return; 115 } 116 logAlways(message + "... retry=" + retry); 117 SystemClock.sleep(500); 118 } 119 fail(message + " failed"); 120 } 121 122 @Nullable getDisplayState(boolean defaultDisplay)123 private static Boolean getDisplayState(boolean defaultDisplay) { 124 final String dump = executeShellCommand("dumpsys display"); 125 final Predicate<Matcher> displayNameMatcher = defaultDisplay 126 ? m -> m.group(0).contains("FLAG_DEFAULT_DISPLAY") 127 : m -> m.group(1).equals(VIRTUAL_DISPLAY_NAME); 128 for (final String line : dump.split("\\n")) { 129 final Matcher matcher = DISPLAY_DEVICE_PATTERN.matcher(line); 130 if (matcher.matches() && displayNameMatcher.test(matcher)) { 131 return "ON".equals(matcher.group(2)); 132 } 133 } 134 return null; 135 } 136 executeShellCommand(String command)137 private static String executeShellCommand(String command) { 138 try { 139 return SystemUtil.runShellCommand(getInstrumentation(), command); 140 } catch (IOException e) { 141 //bubble it up 142 throw new RuntimeException(e); 143 } 144 } 145 } 146