1 /* 2 * Copyright (C) 2022 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 package android.platform.systemui_tapl.ui 17 18 import android.os.SystemClock 19 import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector 20 import android.platform.systemui_tapl.utils.SYSUI_PACKAGE 21 import android.platform.uiautomatorhelpers.DeviceHelpers.assertInvisible 22 import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisibility 23 import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisible 24 import android.platform.uiautomatorhelpers.DeviceHelpers.click 25 import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj 26 import android.platform.uiautomatorhelpers.WaitUtils.ensureThat 27 import android.platform.uiautomatorhelpers.scrollUntilFound 28 import androidx.test.uiautomator.By 29 import com.android.launcher3.tapl.LauncherInstrumentation 30 import com.android.systemui.shared.system.ActivityManagerWrapper 31 import java.time.Duration 32 import java.util.regex.Pattern 33 34 /** 35 * System UI test automation object representing a media projection permission dialog for sharing 36 * the user's screen to another app. 37 * 38 * https://screenshot.googleplex.com/9YU3VqEh2uiTQ34 (single app) and 39 * https://screenshot.googleplex.com/AE5gqPJ3DE3jo7g (entire screen). 40 */ 41 class MediaProjectionPermissionDialog internal constructor() { 42 43 init { 44 assertSpinnerVisibility(visible = true) 45 } 46 startSingleTaskSharenull47 fun startSingleTaskShare() { 48 waitForObj(SPINNER_SELECTOR).click() 49 50 // Make sure clicking one the pop-up option, not the spinner with the same text 51 waitForObj(POP_UP).waitForObj(SINGLE_APP_SELECTOR) { "Single app option not found" }.click() 52 waitForObj(DIALOG).scrollUntilFound(SINGLE_APP_START_SELECTOR) 53 ?: error("Start button not found") 54 55 // TODO(b/333510487): Sleep is temporarily needed after scroll, and should be remove later 56 SystemClock.sleep(SHORT_TIMEOUT.toMillis()) 57 SINGLE_APP_START_SELECTOR.click() 58 ensureThat("App selector is launched") { isAppSelectorRunning() } 59 } 60 isAppSelectorRunningnull61 private fun isAppSelectorRunning(): Boolean { 62 val tasks = ActivityManagerWrapper.getInstance().getRunningTasks(false) 63 return tasks.any { it.topActivity?.className?.contains(APP_SELECTOR_ACTIVITY) ?: false } 64 } 65 cancelnull66 fun cancel() { 67 waitForObj(CANCEL_SELECTOR) { "Cancel button not found" }.click() 68 } 69 70 /* Dismisses the dialog by the Back gesture */ dismissnull71 fun dismiss() { 72 LauncherInstrumentation().pressBack() 73 assertSpinnerVisibility(visible = false) 74 } 75 assertSingleAppOptionIsDefaultnull76 fun assertSingleAppOptionIsDefault() { 77 // Single App option should be visible without clicking on the spinner 78 SINGLE_APP_SELECTOR.assertVisible() 79 } 80 assertEntireScreenOptionIsDefaultnull81 fun assertEntireScreenOptionIsDefault() { 82 // Entire screen option should be visible without clicking on the spinner 83 ENTIRE_SCREEN_SELECTOR.assertVisible() 84 } 85 assertSingleAppOptionDisablednull86 fun assertSingleAppOptionDisabled() { 87 waitForObj(SPINNER_SELECTOR).click() 88 SINGLE_APP_DISABLED_SELECTOR.assertVisible() 89 ensureThat("Single app is disabled") { !waitForObj(SINGLE_APP_SELECTOR).isEnabled } 90 } 91 assertSingleAppOptionEnablednull92 fun assertSingleAppOptionEnabled() { 93 waitForObj(SPINNER_SELECTOR).click() 94 SINGLE_APP_DISABLED_SELECTOR.assertInvisible() 95 ensureThat("Single app is enabled") { waitForObj(SINGLE_APP_SELECTOR).isEnabled } 96 } 97 assertSecondaryDisplayVisiblenull98 fun assertSecondaryDisplayVisible() { 99 waitForObj(SPINNER_SELECTOR).click() 100 ENTIRE_SCREEN_RECORD_SECONDARY_SELECTOR.assertVisible() 101 } 102 103 companion object { 104 private val DIALOG = sysuiResSelector("screen_share_permission_dialog") 105 106 // Builds from 24Q3 and earlier will have screen_share_mode_spinner, while builds from 107 // 24Q4 onwards will have screen_share_mode_options, so need to check both options here 108 private val SPINNER_SELECTOR = 109 By.res(Pattern.compile("$SYSUI_PACKAGE:id/screen_share_mode_(options|spinner)")) 110 111 private val POP_UP = By.clazz("android.widget.ListView") 112 private val SINGLE_APP_SELECTOR = By.text("Share one app") 113 private val ENTIRE_SCREEN_SELECTOR = By.text("Share entire screen") 114 private val ENTIRE_SCREEN_RECORD_SECONDARY_SELECTOR = 115 By.text("Record entire screen: Overlay #1") 116 private val SINGLE_APP_START_SELECTOR = By.text("Next") 117 private val CANCEL_SELECTOR = By.text("Cancel") 118 private val SINGLE_APP_DISABLED_SELECTOR = By.textEndsWith("has disabled this option") 119 private const val APP_SELECTOR_ACTIVITY = "MediaProjectionAppSelectorActivity" 120 private val SHORT_TIMEOUT = Duration.ofMillis(500) 121 122 // Public as it is used in Root.java 123 @JvmStatic assertSpinnerVisibilitynull124 fun assertSpinnerVisibility(visible: Boolean) { 125 assertVisibility(SPINNER_SELECTOR, visible) 126 } 127 } 128 } 129