/* * Copyright (C) 2025 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.platform.systemui_tapl.ui.quicksettings import android.graphics.PointF import android.graphics.Rect import android.platform.systemui_tapl.utils.DeviceUtils.LONG_WAIT import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector import android.platform.uiautomatorhelpers.BetterSwipe import android.platform.uiautomatorhelpers.DeviceHelpers.assertInvisible import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisible import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj import android.platform.uiautomatorhelpers.PRECISE_GESTURE_INTERPOLATOR import android.view.Display.DEFAULT_DISPLAY import androidx.test.uiautomator.UiObject2 import com.android.systemui.Flags import com.google.common.truth.Truth.assertThat import java.time.Duration /** System UI test automation object representing the quick settings' brightness slider. */ class BrightnessSlider internal constructor(private val displayId: Int = DEFAULT_DISPLAY) { private val slider: UiObject2 init { val selector = sliderSelector(displayId) slider = waitForObj(selector, LONG_WAIT) { "$selector not found" } .waitForObj(sysuiResSelector(UI_TOGGLE_SEEKBAR_ID, displayId)) } /** Slides from left to right */ fun swipeFromLeftToRight() { swipeFromLeftToRight(Duration.ofMillis(500)) } /** Slides from left to right with specifying [swipeDuration] */ fun swipeFromLeftToRight(swipeDuration: Duration) { val sliderBounds = slider.visibleBounds val pointFrom = PointF( (sliderBounds.centerX() - sliderBounds.width() / 3).toFloat(), sliderBounds.centerY().toFloat(), ) val pointTo = PointF( (sliderBounds.centerX() + sliderBounds.width() / 3).toFloat(), sliderBounds.centerY().toFloat(), ) // NOTE: This control logic is less than clean. if (Flags.qsUiRefactorComposeFragment() || Flags.sceneContainer()) { BetterSwipe.swipe( pointFrom, pointTo, swipeDuration, PRECISE_GESTURE_INTERPOLATOR, displayId, ) // In this case, the slider is moved to an overlay, then we verify: // The notification shade is not visible, but sysuiResSelector(UI_NOTIFICATION_SHADE_ID, displayId).assertInvisible() // The actual slider is visible, and sysuiResSelector(UI_BRIGHTNESS_SLIDER_ID, displayId).assertVisible() // The bounds haven't changed. assertThat(slider.visibleBounds).isEqualTo(sliderBounds) } else { var mirrorBounds: Rect? = null BetterSwipe.swipe(pointFrom, displayId) { to(pointTo, swipeDuration, PRECISE_GESTURE_INTERPOLATOR) mirrorBounds = brightnessSliderMirror.visibleBounds assertThat(sliderBounds).isEqualTo(mirrorBounds) } assertThat(mirrorBounds).isEqualTo(slider.visibleBounds) } } // The Mirror slider has the same id as the original one, so we get it from the container private val brightnessSliderMirror: UiObject2 get() { // The Mirror slider has the same id as the original one, so we get it from the // container return waitForObj(sysuiResSelector(UI_BRIGHTNESS_MIRROR_CONTAINER_ID, displayId)) .waitForObj(sysuiResSelector(UI_TOGGLE_SEEKBAR_ID, displayId)) } companion object { private const val UI_TOGGLE_SEEKBAR_ID = "slider" private const val UI_BRIGHTNESS_SLIDER_ID = "brightness_slider" private const val UI_BRIGHTNESS_MIRROR_CONTAINER_ID = "brightness_mirror_container" private const val UI_NOTIFICATION_SHADE_ID = "notification_shade" fun sliderSelector(displayId: Int = DEFAULT_DISPLAY) = sysuiResSelector(UI_BRIGHTNESS_SLIDER_ID, displayId) } }