1 /* <lambda>null2 * Copyright (C) 2024 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.platform.systemui_tapl.ui 18 19 import android.graphics.PointF 20 import android.platform.helpers.CommonUtils 21 import android.platform.systemui_tapl.ui.Bubble.Companion.bubbleViews 22 import android.platform.systemui_tapl.utils.DeviceUtils.launcherResSelector 23 import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector 24 import android.platform.uiautomatorhelpers.BetterSwipe 25 import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisible 26 import android.platform.uiautomatorhelpers.DeviceHelpers.context 27 import android.platform.uiautomatorhelpers.DeviceHelpers.hasObject 28 import android.platform.uiautomatorhelpers.DeviceHelpers.uiDevice 29 import android.platform.uiautomatorhelpers.DeviceHelpers.waitForNullableObj 30 import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj 31 import android.platform.uiautomatorhelpers.FLING_GESTURE_INTERPOLATOR 32 import android.view.WindowInsets 33 import android.view.WindowManager 34 import android.view.WindowMetrics 35 import androidx.test.uiautomator.UiObject2 36 import com.android.launcher3.tapl.LauncherInstrumentation 37 import com.google.common.truth.Truth.assertWithMessage 38 import java.time.Duration 39 import java.time.temporal.ChronoUnit.MILLIS 40 41 /** System UI test automation object representing the expanded bubble stack. */ 42 class ExpandedBubbleStack internal constructor() { 43 init { 44 BUBBLE_EXPANDED_VIEW.assertVisible(timeout = FIND_OBJECT_TIMEOUT) { 45 "Bubbles expanded view should be visible" 46 } 47 } 48 49 /** Returns all bubbles. */ 50 val bubbles: List<Bubble> 51 get() = bubbleViews.map { bubbleView: UiObject2 -> Bubble(bubbleView) } 52 53 /** Clicks the overflow button and returns the overflow panel that appears. */ 54 fun openOverflow(): BubbleOverflow { 55 bubbleOverflow.click() 56 return BubbleOverflow() 57 } 58 59 /** Closes the stack by swiping up. */ 60 fun closeBySwiping() { 61 val windowBounds = windowMetrics.bounds 62 val x = windowBounds.width() / 2f 63 // Move up by 1 pixel to ensure tap begins on screen. 64 val startY = windowBounds.bottom - 1f 65 // From bottom middle of screen 66 val from = PointF(x, startY) 67 // To middle of screen 68 val to = PointF(x, startY / 2) 69 // Use a custom duration for bubble swipe to reduce flakiness on slow device. 70 BetterSwipe.swipe( 71 from, 72 to, 73 duration = Duration.of(700, MILLIS), 74 interpolator = FLING_GESTURE_INTERPOLATOR, 75 ) 76 Root.get().verifyNoExpandedBubbleIsVisible() 77 } 78 79 /** Closes the stack by the "back" gesture. */ 80 fun closeByBackGesture() { 81 LauncherInstrumentation().pressBack() 82 Root.get().verifyNoExpandedBubbleIsVisible() 83 } 84 85 /** Closes the stack by clicking outside. */ 86 fun closeByClickingOutside() { 87 val gestureInsets = 88 windowMetrics.windowInsets.getInsetsIgnoringVisibility( 89 WindowInsets.Type.mandatorySystemGestures() or WindowInsets.Type.displayCutout() 90 ) 91 val clickX = gestureInsets.left 92 val clickY = gestureInsets.top 93 uiDevice.click(clickX, clickY) 94 Root.get().verifyNoExpandedBubbleIsVisible() 95 } 96 97 /** Dismiss Manage education to proceed with expanded bubbles */ 98 fun dismissManageEducation() { 99 if (hasObject(BUBBLE_MANAGE_EDUCATION)) { 100 waitForObj(BUBBLE_GOT_IT_BUTTON).click() 101 uiDevice.waitForIdle() 102 } 103 } 104 105 companion object { 106 val FIND_OBJECT_TIMEOUT = Duration.ofSeconds(20) 107 val BUBBLE_EXPANDED_VIEW = sysuiResSelector("bubble_expanded_view") 108 private val BUBBLE_OVERFLOW_BUTTON = sysuiResSelector("bubble_overflow_button") 109 private val BUBBLE_BAR_OVERFLOW = launcherResSelector("bubble_overflow_button") 110 private val BUBBLE_MANAGE_EDUCATION = sysuiResSelector("manage_education_view") 111 private val BUBBLE_GOT_IT_BUTTON = sysuiResSelector("got_it") 112 113 private val windowMetrics: WindowMetrics 114 get() = context.getSystemService(WindowManager::class.java)!!.currentWindowMetrics 115 116 @JvmStatic 117 internal val bubbleOverflow: UiObject2 118 get() { 119 val bubbleOverflow = 120 if (CommonUtils.isLargeScreen()) { 121 // Check bubble bar first if we're large screen 122 waitForNullableObj(BUBBLE_BAR_OVERFLOW, timeout = FIND_OBJECT_TIMEOUT) 123 ?: 124 // Check floating in case bubble bar wasn't active 125 waitForNullableObj( 126 BUBBLE_OVERFLOW_BUTTON, 127 timeout = FIND_OBJECT_TIMEOUT, 128 ) 129 } else { 130 waitForNullableObj(BUBBLE_OVERFLOW_BUTTON, timeout = FIND_OBJECT_TIMEOUT) 131 } 132 assertWithMessage("Bubble overflow not visible").that(bubbleOverflow).isNotNull() 133 return bubbleOverflow!! 134 } 135 } 136 } 137