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.graphics.Point 19 import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector 20 import android.platform.systemui_tapl.volume.panel.ui.VolumePanel 21 import android.platform.uiautomatorhelpers.BetterSwipe 22 import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisible 23 import android.platform.uiautomatorhelpers.DeviceHelpers.click 24 import android.platform.uiautomatorhelpers.DeviceHelpers.uiDevice 25 import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj 26 import android.platform.uiautomatorhelpers.PRECISE_GESTURE_INTERPOLATOR 27 import androidx.test.uiautomator.BySelector 28 import com.android.systemui.Flags 29 import com.google.common.truth.Truth 30 31 /** System UI test automation object representing the dialog for adjusting the device volume. */ 32 class VolumeDialog internal constructor() { 33 init { 34 assertVolumeDialogVisible() 35 } 36 37 /** 38 * Changes the volume by dragging the volume slider. 39 * 40 * Note: Volume value cannot be more than 25 and less than 0. 41 * 42 * @param volume new volume value 43 */ setVolumeByDraggingnull44 fun setVolumeByDragging(volume: Int) { 45 assertVolumeDialogVisible() 46 dragAndChangeVolume(volume) 47 assertVolumeDialogVisible() 48 } 49 50 /** Open the ringer drawer by clicking the ringer mode icon on the volume dialog. */ openRingerDrawernull51 fun openRingerDrawer(): VolumeRingerDrawer { 52 val ringerIconSelector = 53 if (Flags.volumeRedesign()) { 54 sysuiResSelector("ringer_buttons_background") 55 } else { 56 sysuiResSelector("volume_new_ringer_active_icon_container") 57 } 58 waitForObj(ringerIconSelector).click() 59 return VolumeRingerDrawer.get() 60 } 61 62 /** Open the volume setting panel by clicking the setting icon on the volume dialog. */ 63 @Deprecated( 64 "This new volume panel is rolled out. Use openNewVolumePanel instead", 65 replaceWith = ReplaceWith("openNewVolumePanel"), 66 ) openVolumePanelnull67 fun openVolumePanel(): VolumePanelDialog { 68 if (Flags.volumeRedesign()) { 69 sysuiResSelector("volume_dialog_settings").click() 70 } else { 71 sysuiResSelector("settings").click() 72 } 73 return VolumePanelDialog() 74 } 75 76 /** Open the volume setting panel by clicking the setting icon on the volume dialog. */ openNewVolumePanelnull77 fun openNewVolumePanel(): VolumePanel { 78 if (Flags.volumeRedesign()) { 79 waitForObj(sysuiResSelector("volume_dialog_settings")).click() 80 } else { 81 waitForObj(sysuiResSelector("settings")).click() 82 } 83 return VolumePanel() 84 } 85 86 /** 87 * Click the live caption button on the volume dialog. 88 * 89 * https://hsv.googleplex.com/4767031439130624 90 * 91 * @return this 92 */ toggleLiveCaptionsnull93 fun toggleLiveCaptions(): VolumeDialog { 94 waitForObj(sysuiResSelector("odi_captions_icon")).click() 95 return this 96 } 97 98 companion object { 99 val PAGE_TITLE_SELECTOR = sysuiResSelector("volume_dialog") 100 private const val MAX_VOLUME = 26 101 private const val MIN_VOLUME = -1 102 103 /** 104 * Method used for dragging and changing the volume. Note: Volume value cannot be more than 105 * 25 and less than 0. 106 * 107 * @param volume value for volume to changed 108 */ dragAndChangeVolumenull109 private fun dragAndChangeVolume(volume: Int) { 110 val slider = 111 if (Flags.volumeRedesign()) { 112 sysuiResSelector("volume_dialog_slider") 113 } else { 114 sysuiResSelector("volume_row_slider") 115 } 116 val coordinates = getDragCoordinates(slider, volume) 117 assertVolumeDialogVisible() 118 BetterSwipe.swipe( 119 waitForObj(slider).visibleCenter, 120 coordinates, 121 interpolator = PRECISE_GESTURE_INTERPOLATOR, 122 ) 123 } 124 125 /** Asserts that the volume dialog is visible. */ assertVolumeDialogVisiblenull126 private fun assertVolumeDialogVisible() { 127 PAGE_TITLE_SELECTOR.assertVisible() 128 } 129 130 /** 131 * This will get the co-ordinate of the for volume slider based on the volume value 132 * provided. 133 * 134 * Note: Volume value cannot be more than 25 and less than 0. 135 * 136 * Formula's used: Suppose volume slider length is 100 and volume provided is 15, therefore 137 * slider should move to: 138 * 139 * FORMULA: (Volume Provided / Max Volume) * Slider Length Hence in current scenario its: 140 * (15/25)*100 141 * 142 * Since the Android device coordinate works from top to down 143 * [https://screenshot.googleplex .com/Zm3s1rqJ2Es], therefore formula used for coordinate 144 * calculation is: 145 * 146 * X-Coordinate: TOP + ((MAX VOLUME - GIVEN VOLUME)/MAX VOLUME ) * (SLIDER BOTTOM Y 147 * COORDINATE - SLIDER TOP Y COORDINATE) 148 * 149 * Y-Coordinate: SLIDER LEFT X COORDINATE + (SLIDER RIGHT X COORDINATE - SLIDER LEFT X 150 * COORDINATE) / 2 151 * 152 * @param volume value for volume to changed 153 * @return an of Point which is the coordinate of the slider to be moved too. 154 */ getDragCoordinatesnull155 private fun getDragCoordinates(slider: BySelector, volume: Int): Point { 156 Truth.assertThat(volume).isLessThan(MAX_VOLUME) 157 Truth.assertThat(volume).isGreaterThan(MIN_VOLUME) 158 val dimension = uiDevice.waitForObj(slider).visibleBounds 159 val top = dimension.top 160 val left = dimension.left 161 val right = dimension.right 162 val bottom = dimension.bottom 163 val y = (top + (25 - volume).toFloat() / 25 * (bottom - top)).toInt() 164 val x = left + (right - left) / 2 165 return Point(x, y) 166 } 167 } 168 } 169