Use ComponentName for VirtualDisplayService
This CL also moves DisplayHelper class to CTS APK as VirtualDisplayHelper,
and consolidates constants.
Bug: 73349193
Bug: 74043419
Test: No new test starts failing.
atest CtsActivityManagerDeviceTestCases:ActivityManagerMultiDisplayTests
Change-Id: I4930715d3861dcc19ef2a97aeccc1a2fda965f10
diff --git a/tests/framework/base/activitymanager/Android.mk b/tests/framework/base/activitymanager/Android.mk
index 797610a..56db56d 100644
--- a/tests/framework/base/activitymanager/Android.mk
+++ b/tests/framework/base/activitymanager/Android.mk
@@ -32,13 +32,13 @@
$(call all-named-files-under,Components.java, appPrereleaseSdk) \
$(call all-named-files-under,Components.java, appSecondUid) \
$(call all-named-files-under,Components.java, appThirdUid) \
+ $(call all-named-files-under,Components.java, displayserviceapp) \
$(call all-named-files-under,Components.java, translucentapp) \
$(call all-named-files-under,Components.java, translucentappsdk26) \
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- cts-amwm-util \
- cts-display-service-app-util
+ cts-amwm-util
LOCAL_CTS_TEST_PACKAGE := android.server
diff --git a/tests/framework/base/activitymanager/displayserviceapp/Android.mk b/tests/framework/base/activitymanager/displayserviceapp/Android.mk
index b798d87..a844068 100644
--- a/tests/framework/base/activitymanager/displayserviceapp/Android.mk
+++ b/tests/framework/base/activitymanager/displayserviceapp/Android.mk
@@ -12,4 +12,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-include $(call all-subdir-makefiles)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-am-app-base
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+
+LOCAL_SDK_VERSION := test_current
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_PACKAGE_NAME := CtsDisplayServiceApp
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/framework/base/activitymanager/displayserviceapp/app/AndroidManifest.xml b/tests/framework/base/activitymanager/displayserviceapp/AndroidManifest.xml
similarity index 79%
rename from tests/framework/base/activitymanager/displayserviceapp/app/AndroidManifest.xml
rename to tests/framework/base/activitymanager/displayserviceapp/AndroidManifest.xml
index 4051804..8e9df70 100644
--- a/tests/framework/base/activitymanager/displayserviceapp/app/AndroidManifest.xml
+++ b/tests/framework/base/activitymanager/displayserviceapp/AndroidManifest.xml
@@ -14,13 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="android.server.am.displayservice">
- <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ package="android.server.am.displayservice">
+
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
+
<application android:label="CtsDisplayService">
- <service android:name=".VirtualDisplayService"
- android:exported="true" />
+ <service
+ android:name=".VirtualDisplayService"
+ android:exported="true" />
</application>
</manifest>
diff --git a/tests/framework/base/activitymanager/displayserviceapp/app/Android.mk b/tests/framework/base/activitymanager/displayserviceapp/app/Android.mk
deleted file mode 100644
index c9cb7ef..0000000
--- a/tests/framework/base/activitymanager/displayserviceapp/app/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2017 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 := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-
-LOCAL_SDK_VERSION := test_current
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_PACKAGE_NAME := CtsDisplayServiceApp
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/framework/base/activitymanager/displayserviceapp/src/android/server/am/displayservice/Components.java b/tests/framework/base/activitymanager/displayserviceapp/src/android/server/am/displayservice/Components.java
new file mode 100644
index 0000000..76d4d8f
--- /dev/null
+++ b/tests/framework/base/activitymanager/displayserviceapp/src/android/server/am/displayservice/Components.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.server.am.displayservice;
+
+import android.content.ComponentName;
+import android.server.am.component.ComponentsBase;
+
+public class Components extends ComponentsBase {
+
+ public static final ComponentName VIRTUAL_DISPLAY_SERVICE = component(
+ Components.class, "VirtualDisplayService");
+
+ /**
+ * Constants for {@link android.server.am.displayservice.VirtualDisplayService}.
+ */
+ public static final class VirtualDisplayService {
+ public static final String VIRTUAL_DISPLAY_NAME = "CtsVirtualDisplay";
+ // String extra key for command. Value should be one of COMMAND_* below.
+ public static final String EXTRA_COMMAND = "command";
+ // Boolean extra key to show keyguard on the display.
+ public static final String EXTRA_SHOW_CONTENT_WHEN_LOCKED = "show_content_when_locked";
+ // Extra values for {@link #EXTRA_COMMAND}.
+ public static final String COMMAND_CREATE = "create";
+ public static final String COMMAND_DESTROY = "destroy";
+ public static final String COMMAND_OFF = "off";
+ public static final String COMMAND_ON = "on";
+ }
+}
diff --git a/tests/framework/base/activitymanager/displayserviceapp/app/src/android/server/am/displayservice/VirtualDisplayService.java b/tests/framework/base/activitymanager/displayserviceapp/src/android/server/am/displayservice/VirtualDisplayService.java
similarity index 60%
rename from tests/framework/base/activitymanager/displayserviceapp/app/src/android/server/am/displayservice/VirtualDisplayService.java
rename to tests/framework/base/activitymanager/displayserviceapp/src/android/server/am/displayservice/VirtualDisplayService.java
index bf6b87e..e3aaefa 100644
--- a/tests/framework/base/activitymanager/displayserviceapp/app/src/android/server/am/displayservice/VirtualDisplayService.java
+++ b/tests/framework/base/activitymanager/displayserviceapp/src/android/server/am/displayservice/VirtualDisplayService.java
@@ -18,6 +18,15 @@
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
+import static android.server.am.displayservice.Components.VirtualDisplayService.COMMAND_CREATE;
+import static android.server.am.displayservice.Components.VirtualDisplayService.COMMAND_DESTROY;
+import static android.server.am.displayservice.Components.VirtualDisplayService.COMMAND_OFF;
+import static android.server.am.displayservice.Components.VirtualDisplayService.COMMAND_ON;
+import static android.server.am.displayservice.Components.VirtualDisplayService.EXTRA_COMMAND;
+import static android.server.am.displayservice.Components.VirtualDisplayService
+ .EXTRA_SHOW_CONTENT_WHEN_LOCKED;
+import static android.server.am.displayservice.Components.VirtualDisplayService
+ .VIRTUAL_DISPLAY_NAME;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -28,15 +37,16 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.ImageReader;
-import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
-import android.view.Surface;
public class VirtualDisplayService extends Service {
- private static final String NOTIFICATION_CHANNEL_ID = "cts/VirtualDisplayService";
- private static final String TAG = "VirtualDisplayService";
+ private static final String TAG = VirtualDisplayService.class.getSimpleName();
+ /** See {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD}. */
+ private static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
+
+ private static final String NOTIFICATION_CHANNEL_ID = "cts/VirtualDisplayService";
private static final int FOREGROUND_ID = 1;
private static final int DENSITY = 160;
@@ -52,8 +62,8 @@
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(new NotificationChannel(
- NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
- NotificationManager.IMPORTANCE_DEFAULT));
+ NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
+ NotificationManager.IMPORTANCE_DEFAULT));
Notification notif = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(android.R.drawable.ic_dialog_alert)
.build();
@@ -62,18 +72,23 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- String command = intent.getStringExtra("command");
+ String command = intent.getStringExtra(EXTRA_COMMAND);
Log.d(TAG, "Got command: " + command);
- if ("create".equals(command)) {
- createVirtualDisplay(intent);
- } if ("off".equals(command)) {
- mVirtualDisplay.setSurface(null);
- } else if ("on".equals(command)) {
- mVirtualDisplay.setSurface(mReader.getSurface());
- } else if ("destroy".equals(command)) {
- destroyVirtualDisplay();
- stopSelf();
+ switch (command) {
+ case COMMAND_CREATE:
+ createVirtualDisplay(intent);
+ break;
+ case COMMAND_OFF:
+ mVirtualDisplay.setSurface(null);
+ break;
+ case COMMAND_ON:
+ mVirtualDisplay.setSurface(mReader.getSurface());
+ break;
+ case COMMAND_DESTROY:
+ destroyVirtualDisplay();
+ stopSelf();
+ break;
}
return START_NOT_STICKY;
@@ -88,14 +103,13 @@
mReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
final DisplayManager displayManager = getSystemService(DisplayManager.class);
- final String name = "CtsVirtualDisplay";
int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
- if (intent.getBooleanExtra("show_content_when_locked", false /* defaultValue */)) {
- flags |= 1 << 5; // VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD
+ if (intent.getBooleanExtra(EXTRA_SHOW_CONTENT_WHEN_LOCKED, false /* defaultValue */)) {
+ flags |= VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
}
mVirtualDisplay = displayManager.createVirtualDisplay(
- name, WIDTH, HEIGHT, DENSITY, mReader.getSurface(), flags);
+ VIRTUAL_DISPLAY_NAME, WIDTH, HEIGHT, DENSITY, mReader.getSurface(), flags);
}
private void destroyVirtualDisplay() {
diff --git a/tests/framework/base/activitymanager/displayserviceapp/util/Android.mk b/tests/framework/base/activitymanager/displayserviceapp/util/Android.mk
deleted file mode 100644
index 613888a..0000000
--- a/tests/framework/base/activitymanager/displayserviceapp/util/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2017 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)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- compatibility-device-util \
- android-support-test
-
-LOCAL_MODULE := cts-display-service-app-util
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/framework/base/activitymanager/displayserviceapp/util/src/android/server/am/displayservice/DisplayHelper.java b/tests/framework/base/activitymanager/displayserviceapp/util/src/android/server/am/displayservice/DisplayHelper.java
deleted file mode 100644
index f541770..0000000
--- a/tests/framework/base/activitymanager/displayserviceapp/util/src/android/server/am/displayservice/DisplayHelper.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2017 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.server.am.displayservice;
-
-import static junit.framework.Assert.assertTrue;
-
-import android.support.test.InstrumentationRegistry;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-import java.io.IOException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class DisplayHelper {
- private static final String VIRTUAL_DISPLAY_NAME = "CtsVirtualDisplay";
- private static final String VIRTUAL_DISPLAY_SERVICE =
- "android.server.am.displayservice/.VirtualDisplayService";
- private static final Pattern mDisplayDevicePattern = Pattern.compile(
- ".*DisplayDeviceInfo\\{\"([^\"]+)\":.*, state (\\S+),.*\\}.*");
-
- private boolean mCreated;
-
- public DisplayHelper() {
- }
-
- public void createAndWaitForDisplay(boolean external, boolean requestShowWhenLocked)
- {
- StringBuilder command =
- new StringBuilder("am startfgservice -n " + VIRTUAL_DISPLAY_SERVICE);
- command.append(" --es command create");
- if (external) {
- command.append(" --ez external_display true");
- }
- if (requestShowWhenLocked) {
- command.append(" --ez show_content_when_locked true");
- }
- executeShellCommand(command.toString());
-
- waitForDisplayState(false /* default */, true /* exists */, true /* on */);
- mCreated = true;
- }
-
- public void turnDisplayOff() {
- executeShellCommand(
- "am start-service -n " + VIRTUAL_DISPLAY_SERVICE + " --es command off");
- waitForDisplayState(false /* default */, true /* exists */, false /* on */);
- }
-
- public void turnDisplayOn() {
- executeShellCommand(
- "am start-service -n " + VIRTUAL_DISPLAY_SERVICE + " --es command on");
- waitForDisplayState(false /* default */, true /* exists */, true /* on */);
- }
-
- public void releaseDisplay() {
- if (mCreated) {
- executeShellCommand(
- "am start-service -n " + VIRTUAL_DISPLAY_SERVICE + " --es command destroy");
- waitForDisplayState(false /* default */, false /* exists */, true /* on */);
- }
- mCreated = false;
- }
-
- public static void waitForDefaultDisplayState(boolean wantOn) {
- waitForDisplayState(true /* default */, true /* exists */, wantOn);
- }
-
- public static boolean getDefaultDisplayState() {
- return getDisplayState(true);
- }
-
- private static void waitForDisplayState(boolean defaultDisplay, boolean wantExists, boolean wantOn) {
- int tries = 0;
- boolean done = false;
- do {
- if (tries > 0) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- // Oh well
- }
- }
-
- Boolean state = getDisplayState(defaultDisplay);
- done = (!wantExists && state == null)
- || (wantExists && state != null && state == wantOn);
-
- tries++;
- } while (tries < 10 && !done);
-
- assertTrue(done);
- }
-
- private static Boolean getDisplayState(boolean defaultDisplay) {
- String dump = executeShellCommand("dumpsys display");
-
- boolean displayExists = false;
- boolean displayOn = false;
- for (String line : dump.split("\\n")) {
- Matcher matcher = mDisplayDevicePattern.matcher(line);
- if (matcher.matches()) {
- if ((defaultDisplay && line.contains("FLAG_DEFAULT_DISPLAY"))
- || (!defaultDisplay && VIRTUAL_DISPLAY_NAME.equals(matcher.group(1)))) {
- return "ON".equals(matcher.group(2));
- }
- }
- }
- return null;
- }
-
- private static String executeShellCommand(String command) {
- try {
- return SystemUtil
- .runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
- } catch (IOException e) {
- //bubble it up
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
index 38deb3a..141cf4b 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
@@ -60,7 +60,6 @@
import android.content.ComponentName;
import android.platform.test.annotations.Presubmit;
import android.server.am.ActivityManagerState.ActivityDisplay;
-import android.server.am.displayservice.DisplayHelper;
import android.support.annotation.Nullable;
import android.support.test.filters.FlakyTest;
@@ -1725,7 +1724,7 @@
private class ExternalDisplaySession implements AutoCloseable {
@Nullable
- private DisplayHelper mExternalDisplayHelper;
+ private VirtualDisplayHelper mExternalDisplayHelper;
/**
* Creates a private virtual display with the external and show with insecure
@@ -1736,9 +1735,8 @@
final List<ActivityDisplay> originalDS = getDisplaysStates();
final int originalDisplayCount = originalDS.size();
- mExternalDisplayHelper = new DisplayHelper();
- mExternalDisplayHelper.createAndWaitForDisplay(true /* external */,
- showContentWhenLocked);
+ mExternalDisplayHelper = new VirtualDisplayHelper();
+ mExternalDisplayHelper.createAndWaitForDisplay(showContentWhenLocked);
// Wait for the virtual display to be created and get configurations.
final List<ActivityDisplay> ds = getDisplayStateAfterChange(originalDisplayCount + 1);
@@ -1773,7 +1771,7 @@
}
}
- private class PrimaryDisplayStateSession implements AutoCloseable {
+ private static class PrimaryDisplayStateSession implements AutoCloseable {
void turnScreenOff() {
setPrimaryDisplayState(false);
@@ -1791,7 +1789,7 @@
} else {
pressSleepButton();
}
- DisplayHelper.waitForDefaultDisplayState(wantOn);
+ VirtualDisplayHelper.waitForDefaultDisplayState(wantOn);
}
}
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/VirtualDisplayHelper.java b/tests/framework/base/activitymanager/src/android/server/am/VirtualDisplayHelper.java
new file mode 100644
index 0000000..3be9101
--- /dev/null
+++ b/tests/framework/base/activitymanager/src/android/server/am/VirtualDisplayHelper.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2017 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.server.am;
+
+import static android.server.am.ComponentNameUtils.getActivityName;
+import static android.server.am.StateLogger.logAlways;
+import static android.server.am.displayservice.Components.VIRTUAL_DISPLAY_SERVICE;
+import static android.server.am.displayservice.Components.VirtualDisplayService.COMMAND_CREATE;
+import static android.server.am.displayservice.Components.VirtualDisplayService.COMMAND_DESTROY;
+import static android.server.am.displayservice.Components.VirtualDisplayService.COMMAND_OFF;
+import static android.server.am.displayservice.Components.VirtualDisplayService.COMMAND_ON;
+import static android.server.am.displayservice.Components.VirtualDisplayService.EXTRA_COMMAND;
+import static android.server.am.displayservice.Components.VirtualDisplayService.EXTRA_SHOW_CONTENT_WHEN_LOCKED;
+import static android.server.am.displayservice.Components.VirtualDisplayService.VIRTUAL_DISPLAY_NAME;
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.fail;
+
+import android.os.SystemClock;
+import android.support.annotation.Nullable;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helper class to create virtual display with communicating with VirtualDisplayService in
+ * CtsDisplayServiceApp.
+ */
+class VirtualDisplayHelper {
+ private static final Pattern DISPLAY_DEVICE_PATTERN = Pattern.compile(
+ ".*DisplayDeviceInfo\\{\"([^\"]+)\":.*, state (\\S+),.*\\}.*");
+
+ private boolean mCreated;
+
+ void createAndWaitForDisplay(boolean requestShowWhenLocked) {
+ StringBuilder command = new StringBuilder("am startfgservice -n "
+ + getActivityName(VIRTUAL_DISPLAY_SERVICE));
+ command.append(" --es " + EXTRA_COMMAND + " " + COMMAND_CREATE);
+ if (requestShowWhenLocked) {
+ command.append(" --ez " + EXTRA_SHOW_CONTENT_WHEN_LOCKED + " true");
+ }
+ executeShellCommand(command.toString());
+
+ waitForDisplayState(false /* default */, true /* on */);
+ mCreated = true;
+ }
+
+ void turnDisplayOff() {
+ executeShellCommand("am start-service -n " + getActivityName(VIRTUAL_DISPLAY_SERVICE)
+ + " --es " + EXTRA_COMMAND + " " + COMMAND_OFF);
+ waitForDisplayState(false /* default */, false /* on */);
+ }
+
+ void turnDisplayOn() {
+ executeShellCommand("am start-service -n " + getActivityName(VIRTUAL_DISPLAY_SERVICE)
+ + " --es " + EXTRA_COMMAND + " " + COMMAND_ON);
+ waitForDisplayState(false /* default */, true /* on */);
+ }
+
+ void releaseDisplay() {
+ if (mCreated) {
+ executeShellCommand("am start-service -n " + getActivityName(VIRTUAL_DISPLAY_SERVICE)
+ + " --es " + EXTRA_COMMAND + " " + COMMAND_DESTROY);
+ waitForDisplayCondition(false /* defaultDisplay */, Objects::isNull,
+ "Waiting for virtual display destroy");
+ }
+ mCreated = false;
+ }
+
+ static void waitForDefaultDisplayState(boolean wantOn) {
+ waitForDisplayState(true /* default */, wantOn);
+ }
+
+ private static void waitForDisplayState(boolean defaultDisplay, boolean wantOn) {
+ waitForDisplayCondition(defaultDisplay, state -> state != null && state == wantOn,
+ "Waiting for " + (defaultDisplay ? "default" : "virtual") + " display "
+ + (wantOn ? "on" : "off"));
+ }
+
+ private static void waitForDisplayCondition(boolean defaultDisplay,
+ Predicate<Boolean> condition, String message) {
+ for (int retry = 1; retry <= 10; retry++) {
+ if (condition.test(getDisplayState(defaultDisplay))) {
+ return;
+ }
+ logAlways(message + "... retry=" + retry);
+ SystemClock.sleep(500);
+ }
+ fail(message + " failed");
+ }
+
+ @Nullable
+ private static Boolean getDisplayState(boolean defaultDisplay) {
+ final String dump = executeShellCommand("dumpsys display");
+ final Predicate<Matcher> displayNameMatcher = defaultDisplay
+ ? m -> m.group(0).contains("FLAG_DEFAULT_DISPLAY")
+ : m -> m.group(1).equals(VIRTUAL_DISPLAY_NAME);
+ for (final String line : dump.split("\\n")) {
+ final Matcher matcher = DISPLAY_DEVICE_PATTERN.matcher(line);
+ if (matcher.matches() && displayNameMatcher.test(matcher)) {
+ return "ON".equals(matcher.group(2));
+ }
+ }
+ return null;
+ }
+
+ private static String executeShellCommand(String command) {
+ try {
+ return SystemUtil.runShellCommand(getInstrumentation(), command);
+ } catch (IOException e) {
+ //bubble it up
+ throw new RuntimeException(e);
+ }
+ }
+}