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.from(from) 71 .to(to, duration = Duration.of(700, MILLIS), interpolator = FLING_GESTURE_INTERPOLATOR) 72 .release() 73 Root.get().verifyNoExpandedBubbleStackIsVisible() 74 } 75 76 /** Closes the stack by the "back" gesture. */ 77 fun closeByBackGesture() { 78 LauncherInstrumentation().pressBack() 79 Root.get().verifyNoExpandedBubbleStackIsVisible() 80 } 81 82 /** Closes the stack by clicking outside. */ 83 fun closeByClickingOutside() { 84 val gestureInsets = 85 windowMetrics.windowInsets.getInsetsIgnoringVisibility( 86 WindowInsets.Type.mandatorySystemGestures() or WindowInsets.Type.displayCutout() 87 ) 88 val clickX = gestureInsets.left 89 val clickY = gestureInsets.top 90 uiDevice.click(clickX, clickY) 91 Root.get().verifyNoExpandedBubbleStackIsVisible() 92 } 93 94 /** Dismiss Manage education to proceed with expanded bubbles */ 95 fun dismissManageEducation() { 96 if (hasObject(BUBBLE_MANAGE_EDUCATION)) { 97 waitForObj(BUBBLE_GOT_IT_BUTTON).click() 98 uiDevice.waitForIdle() 99 } 100 } 101 102 companion object { 103 val FIND_OBJECT_TIMEOUT = Duration.ofSeconds(20) 104 val BUBBLE_EXPANDED_VIEW = sysuiResSelector("bubble_expanded_view") 105 private val BUBBLE_OVERFLOW_BUTTON = sysuiResSelector("bubble_overflow_button") 106 private val BUBBLE_BAR_OVERFLOW = launcherResSelector("bubble_overflow_button") 107 private val BUBBLE_MANAGE_EDUCATION = sysuiResSelector("manage_education_view") 108 private val BUBBLE_GOT_IT_BUTTON = sysuiResSelector("got_it") 109 110 private val windowMetrics: WindowMetrics 111 get() = context.getSystemService(WindowManager::class.java)!!.currentWindowMetrics 112 113 @JvmStatic 114 internal val bubbleOverflow: UiObject2 115 get() { 116 val bubbleOverflow = 117 if (CommonUtils.isLargeScreen()) { 118 // Check bubble bar first if we're large screen 119 waitForNullableObj(BUBBLE_BAR_OVERFLOW, timeout = FIND_OBJECT_TIMEOUT) 120 ?: 121 // Check floating in case bubble bar wasn't active 122 waitForNullableObj( 123 BUBBLE_OVERFLOW_BUTTON, 124 timeout = FIND_OBJECT_TIMEOUT, 125 ) 126 } else { 127 waitForNullableObj(BUBBLE_OVERFLOW_BUTTON, timeout = FIND_OBJECT_TIMEOUT) 128 } 129 assertWithMessage("Bubble overflow not visible").that(bubbleOverflow).isNotNull() 130 return bubbleOverflow!! 131 } 132 } 133 } 134