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.wm; 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.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; 22 import static android.server.wm.ActivityManagerTestBase.isDisplayOn; 23 import static android.server.wm.StateLogger.logAlways; 24 import static android.view.Display.DEFAULT_DISPLAY; 25 26 import static androidx.test.InstrumentationRegistry.getInstrumentation; 27 28 import static org.junit.Assert.fail; 29 30 import android.graphics.PixelFormat; 31 import android.hardware.display.DisplayManager; 32 import android.hardware.display.VirtualDisplay; 33 import android.media.ImageReader; 34 import android.os.SystemClock; 35 36 import com.android.compatibility.common.util.SystemUtil; 37 38 import java.util.function.Predicate; 39 40 /** 41 * Helper class to create virtual display. 42 */ 43 class VirtualDisplayHelper { 44 45 private boolean mPublicDisplay = false; 46 private boolean mCanShowWithInsecureKeyguard = false; 47 private boolean mShowSystemDecorations = false; 48 49 private static final String VIRTUAL_DISPLAY_NAME = "CtsVirtualDisplay"; 50 /** See {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD}. */ 51 private static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5; 52 /** See {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS}. */ 53 private static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9; 54 55 private static final int DENSITY = 160; 56 static final int HEIGHT = 480; 57 static final int WIDTH = 800; 58 59 private ImageReader mReader; 60 private VirtualDisplay mVirtualDisplay; 61 private boolean mCreated; 62 setPublicDisplay(boolean publicDisplay)63 VirtualDisplayHelper setPublicDisplay(boolean publicDisplay) { 64 mPublicDisplay = publicDisplay; 65 return this; 66 } 67 setCanShowWithInsecureKeyguard(boolean canShowWithInsecureKeyguard)68 VirtualDisplayHelper setCanShowWithInsecureKeyguard(boolean canShowWithInsecureKeyguard) { 69 mCanShowWithInsecureKeyguard = canShowWithInsecureKeyguard; 70 return this; 71 } 72 setShowSystemDecorations(boolean showSystemDecorations)73 VirtualDisplayHelper setShowSystemDecorations(boolean showSystemDecorations) { 74 mShowSystemDecorations = showSystemDecorations; 75 return this; 76 } 77 createAndWaitForDisplay()78 int createAndWaitForDisplay() { 79 SystemUtil.runWithShellPermissionIdentity(() -> { 80 createVirtualDisplay(); 81 waitForDisplayState(mVirtualDisplay.getDisplay().getDisplayId() /* default */, 82 true /* on */); 83 mCreated = true; 84 }); 85 return mVirtualDisplay.getDisplay().getDisplayId(); 86 } 87 turnDisplayOff()88 void turnDisplayOff() { 89 SystemUtil.runWithShellPermissionIdentity(() -> { 90 mVirtualDisplay.setSurface(null); 91 waitForDisplayState(mVirtualDisplay.getDisplay().getDisplayId() /* displayId */, 92 false /* on */); 93 }); 94 } 95 turnDisplayOn()96 void turnDisplayOn() { 97 SystemUtil.runWithShellPermissionIdentity(() -> { 98 mVirtualDisplay.setSurface(mReader.getSurface()); 99 waitForDisplayState(mVirtualDisplay.getDisplay().getDisplayId() /* displayId */, 100 true /* on */); 101 }); 102 } 103 releaseDisplay()104 void releaseDisplay() { 105 SystemUtil.runWithShellPermissionIdentity(() -> { 106 if (mCreated) { 107 mVirtualDisplay.release(); 108 mReader.close(); 109 waitForDisplayCondition(mVirtualDisplay.getDisplay().getDisplayId() /* displayId */, 110 onState -> onState != null && onState == false, 111 "Waiting for virtual display destroy"); 112 } 113 mCreated = false; 114 }); 115 } 116 createVirtualDisplay()117 private void createVirtualDisplay() { 118 mReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2); 119 120 final DisplayManager displayManager = getInstrumentation() 121 .getContext().getSystemService(DisplayManager.class); 122 123 int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; 124 125 if (mPublicDisplay) { 126 flags |= VIRTUAL_DISPLAY_FLAG_PUBLIC; 127 } 128 if (mCanShowWithInsecureKeyguard) { 129 flags |= VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; 130 } 131 if (mShowSystemDecorations) { 132 flags |= VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; 133 } 134 135 logAlways("createVirtualDisplay: " + WIDTH + "x" + HEIGHT + ", dpi: " + DENSITY 136 + ", publicDisplay=" + mPublicDisplay 137 + ", canShowWithInsecureKeyguard=" + mCanShowWithInsecureKeyguard 138 + ", showSystemDecorations=" + mShowSystemDecorations); 139 140 mVirtualDisplay = displayManager.createVirtualDisplay( 141 VIRTUAL_DISPLAY_NAME, WIDTH, HEIGHT, DENSITY, mReader.getSurface(), flags); 142 } 143 waitForDefaultDisplayState(boolean wantOn)144 static void waitForDefaultDisplayState(boolean wantOn) { 145 waitForDisplayState(DEFAULT_DISPLAY /* default */, wantOn); 146 } 147 waitForDisplayState(int displayId, boolean wantOn)148 private static void waitForDisplayState(int displayId, boolean wantOn) { 149 waitForDisplayCondition(displayId, state -> state != null && state == wantOn, 150 "Waiting for " + ((displayId == DEFAULT_DISPLAY) ? "default" : "virtual") 151 + " display " 152 + (wantOn ? "on" : "off")); 153 } 154 waitForDisplayCondition(int displayId, Predicate<Boolean> condition, String message)155 private static void waitForDisplayCondition(int displayId, 156 Predicate<Boolean> condition, String message) { 157 for (int retry = 1; retry <= 10; retry++) { 158 if (condition.test(isDisplayOn(displayId))) { 159 return; 160 } 161 logAlways(message + "... retry=" + retry); 162 SystemClock.sleep(500); 163 } 164 fail(message + " failed"); 165 } 166 } 167