• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.controller
18 
19 import android.Manifest.permission
20 import android.content.ContentResolver
21 import android.media.AudioManager
22 import android.os.VibratorManager
23 import android.platform.uiautomatorhelpers.DeviceHelpers.context
24 import android.platform.uiautomatorhelpers.ShellPrivilege
25 import android.platform.uiautomatorhelpers.WaitUtils.ensureThat
26 import android.provider.Settings
27 
28 /** Controller for adjusting the device volume. */
29 class VolumeController private constructor() {
30 
31     private val audioManager: AudioManager =
32         context.getSystemService(AudioManager::class.java)
33             ?: error("Can't get the AudioManager for ${VolumeController::class}}")
34 
35     /** Available ringer modes defined in [AudioManager] */
36     enum class RingerMode(internal val mode: Int) {
37         NORMAL(AudioManager.RINGER_MODE_NORMAL),
38         SILENT(AudioManager.RINGER_MODE_SILENT),
39         VIBRATE(AudioManager.RINGER_MODE_VIBRATE);
40 
41         /** Whether the ringer mode is available on the device under test. */
42         val isAvailable: Boolean
43             get() {
44                 return when (this) {
45                     NORMAL,
46                     SILENT -> true
47                     VIBRATE -> hasVibrator
48                 }
49             }
50     }
51 
52     /**
53      * Adjusts the volume to ADJUST_SAME.
54      *
55      * This method can be used to show the volume dialog.
56      *
57      * Note: ADJUST_SAME here means [AudioManager.ADJUST_SAME]. It tells AudioManager the direction
58      * to change the volume, which is to keep the slider as is.
59      */
adjustVolumeSamenull60     fun adjustVolumeSame() = adjustVolume(AudioManager.ADJUST_SAME)
61 
62     /** Adjusts the volume to ADJUST_LOWER. Shows the volume dialog. */
63     fun adjustVolumeLower() = adjustVolume(AudioManager.ADJUST_LOWER)
64 
65     /** Adjusts the volume to ADJUST_RAISE. Shows the volume dialog. */
66     fun adjustVolumeRaise() = adjustVolume(AudioManager.ADJUST_RAISE)
67 
68     private fun adjustVolume(direction: Int) {
69         audioManager.adjustSuggestedStreamVolume(
70             direction,
71             AudioManager.STREAM_MUSIC,
72             AudioManager.FLAG_SHOW_UI,
73         )
74     }
75 
76     /**
77      * The current Music stream's volume. This setter won't bring up volume dialog. Use
78      * [adjustVolumeSame] instead if you want to open the dialog.
79      */
80     var volume: Int
81         get() = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
82         set(volumeIndex) {
83             audioManager.setStreamVolume(
84                 AudioManager.STREAM_MUSIC,
85                 volumeIndex,
86                 0, // Do nothing, prevent opening UI.
87             )
<lambda>null88             ensureThat("music volume == ${volumeIndex}") { volume == volumeIndex }
89         }
90 
91     /**
92      * Set SysUI's internal ringer mode state.
93      *
94      * Notice that it requires STATUS_BAR_SERVICE permission to complete the setup. If the caller
95      * doesn't have the permission, the function will try to automatically grant the permission for
96      * the caller. However, it may throw [SecurityException] if the caller has called
97      * [android.app.UiAutomation.adoptShellPermissionIdentity] before. Therefore, use this function
98      * carefully.
99      *
100      * @param ringerMode[RingerMode]
101      */
setRingerModeInternalnull102     fun setRingerModeInternal(ringerMode: RingerMode) {
103         ShellPrivilege(permission.STATUS_BAR_SERVICE).use {
104             audioManager.ringerModeInternal = ringerMode.mode
105         }
106     }
107 
108     /**
109      * Sets volume dialog timeout in ms.
110      *
111      * This method is called to set the timeout to a longer value to help the test to recognize its
112      * visibility.
113      *
114      * Use [SetVolumeDialogTimeoutRule] in order to control the timeout value during the test only.
115      *
116      * @param cr content resolver.
117      * @param timeout long press timeout.
118      */
setVolumeDialogTimeoutnull119     fun setVolumeDialogTimeout(cr: ContentResolver, timeout: Int) {
120         Settings.Secure.putInt(cr, Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, timeout)
121     }
122 
123     /** ringerMode is the current available Audio ringer mode. */
124     val ringerMode: RingerMode
125         get() {
126             val ringerMode = audioManager.ringerMode
<lambda>null127             return RingerMode.values().firstOrNull { it.mode == ringerMode }
128                 ?: error("Ringer mode $ringerMode isn't defined in ${RingerMode::class}")
129         }
130 
131     /** Maximum volume of music stream. The value may be different based on the device's setting. */
132     val maxVolume: Int
133         get() = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
134 
135     /** Minimum volume of music stream. The value may be different based on the device's setting. */
136     val minVolume: Int
137         get() = audioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC)
138 
139     companion object {
140         @JvmStatic
141         private val hasVibrator: Boolean
142             get() =
143                 context
144                     .getSystemService(VibratorManager::class.java)!!
145                     .defaultVibrator
146                     .hasVibrator()
147 
148         /** Returns an instance of VolumeController. */
149         @JvmStatic
getnull150         fun get(): VolumeController {
151             return VolumeController()
152         }
153     }
154 }
155